Skip to content

Commit 4517f02

Browse files
Load cached image on init
1 parent 0f5587a commit 4517f02

File tree

1 file changed

+47
-40
lines changed

1 file changed

+47
-40
lines changed

Sources/CachedAsyncImage/CachedAsyncImage.swift

Lines changed: 47 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ import SwiftUI
6565
@available(iOS 15.0, macOS 12.0, tvOS 15.0, watchOS 8.0, *)
6666
public struct CachedAsyncImage<Content>: View where Content: View {
6767

68-
@State private var phase: AsyncImagePhase = .empty
68+
@State private var phase: AsyncImagePhase
6969

7070
private let url: URL?
7171

@@ -79,9 +79,7 @@ public struct CachedAsyncImage<Content>: View where Content: View {
7979

8080
public var body: some View {
8181
content(phase)
82-
.task(id: url) {
83-
await load(url: url)
84-
}
82+
.task(id: url, load)
8583
}
8684

8785
/// Loads and displays an image from the specified URL.
@@ -201,61 +199,70 @@ public struct CachedAsyncImage<Content>: View where Content: View {
201199
self.scale = scale
202200
self.transaction = transaction
203201
self.content = content
204-
loadFromCache(url: url)
205-
}
206-
207-
private func load(url: URL?) async {
208-
guard let url = url else { return }
209-
let request = URLRequest(url: url)
210-
do {
211-
let (data, _) = try await urlSession.data(for: request)
212-
process(data: data, animation: transaction.animation)
213-
} catch {
214-
withAnimation(transaction.animation) {
215-
phase = .failure(error)
216-
}
202+
203+
204+
if let image = cachedImage(from: url, cache: urlCache) {
205+
self._phase = State(wrappedValue: .success(image))
206+
} else {
207+
self._phase = State(wrappedValue: .empty)
217208
}
218209
}
219210

220-
private func loadFromCache(url: URL?) {
221-
guard let url = url else { return }
222-
let request = URLRequest(url: url)
223-
guard let cachedResponse = urlSession.configuration.urlCache?.cachedResponse(for: request) else { return }
224-
process(data: cachedResponse.data)
225-
}
226-
227-
private func process(data: Data, animation: Animation? = nil) {
211+
@Sendable
212+
private func load() async {
228213
do {
229-
#if os(macOS)
230-
if let nsImage = NSImage(data: data) {
231-
let image = Image(nsImage: nsImage)
232-
withAnimation(animation) {
233-
phase = .success(image)
234-
}
235-
} else {
236-
throw AsyncImage<Content>.LoadingError()
237-
}
238-
#else
239-
if let uiImage = UIImage(data: data) {
240-
let image = Image(uiImage: uiImage)
241-
withAnimation(animation) {
214+
if let image = try await remoteImage(from: url, session: urlSession) {
215+
withAnimation(transaction.animation) {
242216
phase = .success(image)
243217
}
244218
} else {
245219
throw AsyncImage<Content>.LoadingError()
246220
}
247-
#endif
248221
} catch {
249-
withAnimation(animation) {
222+
withAnimation(transaction.animation) {
250223
phase = .failure(error)
251224
}
252225
}
253226
}
254227
}
255228

229+
// MARK: - LoadingError
230+
256231
@available(iOS 15.0, macOS 12.0, tvOS 15.0, watchOS 8.0, *)
257232
private extension AsyncImage {
258233

259234
struct LoadingError: Error {
260235
}
261236
}
237+
238+
// MARK: - Helpers
239+
240+
private func remoteImage(from url: URL?, session: URLSession) async throws -> Image? {
241+
guard let url = url else { return nil }
242+
let request = URLRequest(url: url)
243+
let (data, _) = try await session.data(for: request)
244+
return image(from: data)
245+
}
246+
247+
private func cachedImage(from url: URL?, cache: URLCache) -> Image? {
248+
guard let url = url else { return nil }
249+
let request = URLRequest(url: url)
250+
guard let cachedResponse = cache.cachedResponse(for: request) else { return nil }
251+
return image(from: cachedResponse.data)
252+
}
253+
254+
private func image(from data: Data) -> Image? {
255+
#if os(macOS)
256+
if let nsImage = NSImage(data: data) {
257+
return Image(nsImage: nsImage)
258+
} else {
259+
return nil
260+
}
261+
#else
262+
if let uiImage = UIImage(data: data) {
263+
return Image(uiImage: uiImage)
264+
} else {
265+
return nil
266+
}
267+
#endif
268+
}

0 commit comments

Comments
 (0)