Skip to content
 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

8 Commits
 
 
 
 
 
 
 
 

Repository files navigation

CachedAsyncImage-SwiftUI


In this fork https://github.com/MahiAlJawad/CachedAsyncImage-SwiftUI error handling has been added, which was missing in the original.

SwiftUI provides a clean AsyncImage facility to download an asynchronous image and show a placeholder (e.g. ProgressView/Spinner) during image download. However the SwiftUI library does not cache the image, which results in redownloading the image each time. This repo provides a cleaner solution written over the AsyncImage library to support the caching facility.

I have originally answered this solution in a StackOverflow question for image caching: https://stackoverflow.com/a/77956449/18823687 and StackOverflow community found the answer useful. So I have created a repo to share this library in the iOS developer community.

CachedAsyncImage Library

Just copy-paste the following library code in a Swift file

//
//  CachedAsyncImage.swift
//  inSkate
//
//  Created by Dzmitry Sotnikov on 07.03.2026.
//

import SwiftUI

@MainActor
struct AsyncCachedImage<ImageView: View, PlaceholderView: View, ErrorView: View>: View {
    // Input dependencies
    var url: URL?
    @ViewBuilder var content: (Image?) -> ImageView
    @ViewBuilder var placeholder: () -> PlaceholderView
    @ViewBuilder var errorView: () -> ErrorView
    
    // Downloaded image
    @State var image: UIImage?
    
    // Error if occured
    @State var error: Error?
    
    init(
        url: URL?,
        @ViewBuilder content: @escaping (Image?) -> ImageView,
        @ViewBuilder placeholder: @escaping () -> PlaceholderView,
        @ViewBuilder errorView: @escaping () -> ErrorView
    ) {
        self.url = url
        self.content = content
        self.placeholder = placeholder
        self.errorView = errorView
    }
    
    var body: some View {
        VStack {
            if let uiImage = image {
                content(Image(uiImage: uiImage))
            } else if error != nil {
                errorView()
            } else {
                placeholder()
                    .onAppear {
                        Task {
                            image = await downloadPhoto()
                        }
                    }
            }
        }
    }
    
    // Downloads if the image is not cached already
    // Otherwise returns from the cache
    private func downloadPhoto() async -> UIImage? {
        do {
            guard let url else {
                self.error = URLError(.badURL)
                return nil
            }
            
            // Check if the image is cached already
            if
                let cachedResponse = URLCache.shared.cachedResponse(for: .init(url: url)),
                let imageFromCache = UIImage(data: cachedResponse.data)
            {
                return imageFromCache
            } else {
                let (data, response) = try await URLSession.shared.data(from: url)
                
                guard let image = UIImage(data: data) else {
                    self.error = URLError(.cannotDecodeContentData)
                    return nil
                }
                
                // Save returned image data into the cache
                URLCache.shared.storeCachedResponse(.init(response: response, data: data), for: .init(url: url))
                
                return image
            }
        } catch {
            PRINT_DEBUG("Error downloading: \(error)")
            self.error = error
            return nil
        }
    }
}

Usage

Same as original SwiftUI library AsyncImage

        AsyncCachedImage(url: photoURL) { image in
            image
                .resizable()
                .aspectRatio(contentMode: .fill)
        } placeholder: {
            ProgressView() // Shows loading indicator until the image is downloaded
        } errorView: {
            ErrorView() // Your error reaction view
        }

About

Improves SwiftUI's `AsyncImage` library with caching capability

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages