@@ -65,7 +65,7 @@ import SwiftUI
6565@available ( iOS 15 . 0 , macOS 12 . 0 , tvOS 15 . 0 , watchOS 8 . 0 , * )
6666public 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 , * )
257232private 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