CachedAsyncImage is the simplest way to add cache to your AsyncImage.

Overview

CachedAsyncImage πŸ—ƒοΈ

CachedAsyncImage is AsyncImage, but with cache capabilities.

Usage

CachedAsyncImage has the exact same API and behavior as AsyncImage, so you just have to change this:

AsyncImage(url: logoURL)

to this:

CachedAsyncImage(url: logoURL)

In addition to AsyncImage initializers, you have the possibilities to specify the cash you want to use (by default URLCache.shared is used):

CachedAsyncImage(url: logoURL, urlCache: .imageCache)
// URLCache+imageCache.swift

extension URLCache {
    
    static let imageCache = URLCache(memoryCapacity: 512*1000*1000, diskCapacity: 10*1000*1000*1000)
}

Remember when setting the cache the response (in this case our image) must be no larger than about 5% of the disk cache (See this discussion).

Installation

  1. In Xcode, open your project and navigate to File β†’ Swift Packages β†’ Add Package Dependency...
  2. Paste the repository URL (https://github.com/lorenzofiamingo/SwiftUI-CachedAsyncImage) and click Next.
  3. Click Finish.

Other projects

VerticalTabView πŸ”

SharedObject 🍱

Comments
  • URLCache returns nothing before restart

    URLCache returns nothing before restart

    Thanks for the library. I try to use it in a scroll view with transaction animation when an image is loaded:

    CachedAsyncImage(
        url: imageURL,
        urlCache: .imageCache,
        transaction: Transaction(animation: .default)
    ) { phase in
        switch phase {
        case .empty:
            ProgressView()
                .frame(height: 100)
        case .success(let image):
            image
                  .resizable()
        case .failure:
            Image(systemName: "wifi.slash")
        @unknown default:
            EmptyView()
        }
    }
    .frame(maxHeight: 200)
    
    private extension URLCache {
        static let imageCache = URLCache(
            memoryCapacity: 512 * 1000 * 1000,
            diskCapacity: 10 * 1000 * 1000 * 1000
        )
    }
    
    

    But once an image is loaded it continues to animate cell appearance (and other View content) when scrolling down and up again. URLCache doesn't return anything before the app relaunch.

    opened by denis-obukhov 12
  • transaction: Transaction(animation: .easeInOut) does not appear to work

    transaction: Transaction(animation: .easeInOut) does not appear to work

    Great job on this! I was having a huge problem with AsyncImage redownloading images in lazy stacks that this lib completely eliminates.

    The one difference I noticed is that transaction animations don't appear to work. I had a nice ease animation with AsyncImage that does not trigger when I swap it with CachedAsyncImage. Here's my body

    var body: some View { GeometryReader { geo in AsyncImage( url: url, transaction: Transaction(animation: .easeInOut) ) { phase in switch phase { case .empty: Rectangle() .fill(Color.gray1) case let .success(image): image.resizable() .scaledToFill() case .failure: Rectangle() .fill(Color.gray1) @unknown default: EmptyView() } } .frame(width: geo.size.width, height: geo.size.height) .clipped() } } }

    opened by recurrence 6
  • Is 404 counted as an error?

    Is 404 counted as an error?

    It seems after I switched from AsyncImage to your CachedAsyncImage, 404 is no longer an error. Thus when the code tried to load an URL that returned 404, the code would never reach phase.error, thus a placeholder is always showing.

    opened by livid 3
  • Use provided transition on cache hit

    Use provided transition on cache hit

    When provided with an URL that ends up being redirected (301), no cache hit occurs during initialization, as URLCache.cachedResponse expects the redirected URL to be provided instead. This leads to _phase being set to .empty, even though the ensuing .load call will result in a cache hit, because URLSession.data does behave properly.

    ... that's my theory, at least 😬

    I saw, that f24cfe71158f428e9a396a19335221f0fe19e10e did away with animating on cache hit. What was the reason for that change?

    opened by PhilipTrauner 2
  • "EMPTY" printed on empty image state

    There is a print statement here that I don't think should be included because having no URL is a valid state and the print doesn't seem to have any purpose. The current inclusion of the statement spams my console since I use this library to asynchronously load a list of users.

    I'd personally like to see it removed or at least have it made toggleable so I don't have to see it.

    As of 3/1/22 the master branch has this issue.

    opened by ImTheSquid 2
  • Transaction doesn't work

    Transaction doesn't work

    Good work, thanks, Lorenzo! Im using library to fetch and cache images like this:

           CachedAsyncImage(
            url: URL(string: path),
            urlCache: .imageCache,
            transaction: Transaction(animation: .easeInOut)) { phase in
                
                switch phase {
                case .empty:
                    ProgressView()
                        .progressViewStyle(.circular)
                case .success(let image):
                    image
                        .resizable()
                        .aspectRatio(contentMode: .fill)
                case .failure:
                    Image("")
                @unknown default:
                    Image("")
                }
            }
            .frame(
                width: frameForBaseImage().0,
                height: frameForBaseImage().1
            )
            .cornerRadius(filesGroupingSelection == .yearGrouping ? 4 : 8)
    

    But transaction doesn't work at all(

    opened by polkandra 1
  • Question -  Where in the code does caching occur?

    Question - Where in the code does caching occur?

    First off, amazing work! Thanks πŸ™

    I was debugging an issue I have with images no caching correctly (likely due to size or cookies?) and it got me going through the code.

    Could you point me to where the caching occurs? I only see one storeCachedResponse that in my case never gets triggered because there aren't any redirects.

    Does the session automatically do it in this line: let (data, _, metrics) = try await session.data(for: request)? I was under the likely incorrect impression we had to explicitly call storeCachedResponse.

    opened by alfonsogarza 1
  • Question - Is an in-memory cache?

    Question - Is an in-memory cache?

    I mean, will the image still be cached after I exit and re-enter the app, or is just while the app is "alive"? For example I open the app today, and then I open it again in the next month, will the image be still cached?

    Thank you!

    opened by sebasira 1
  • Archive Failing

    Archive Failing

    Whenever I archive with your SPM it fails. I was doing a little reading into the matter, and it seems that you're missing some things in your Package.swift file that is causing the problem.

    platforms: [ .iOS(.v15) ],

    opened by hobbesthetige 1
  • ScrollView + LazyVGrid jumps around when scrolling backward

    ScrollView + LazyVGrid jumps around when scrolling backward

    I have a LazyVGrid inside a Scrollview.. scrolling from start to finish works great , as I scroll backward the scrollview jumps around.. I think the issue is the scrollview content size for each grid item is changing. If I hard code the frame of the image it no longer hitches. I think I should be able to do that as all my images are the same size.. but I didn't run into this issue when trying other image caching frameworks like SDWebImageSwiftUI for example. Just thought you might want to know if it's something that can be looked at.

    
    ScrollView {
    
        LazyVGrid(columns: columnLayout) {
    
            ForEach(settings.wallpaperDataFiltered, id: \.guid) { wallpaper in
    
                ZStack {
                    NavigationLink(destination: WallpaperUI()) {
                       
                        KFImage.url(URL(string: wallpaper.thumbUrl))
                                  .fade(duration: 0.25)
                                  .resizable()
                                  .aspectRatio(contentMode: .fit)
                            
                    }
                
                }
    
            }
    
        }
    
    }
    
    opened by danielkramer 0
  • Loading from cache slowing down animations

    Loading from cache slowing down animations

    Hello @lorenzofiamingo, thank you for this great library! However when the image is really big, it seems like loading from cache slows down main UI thread. Could this operation be moved to background thread by any chance? When initially loading from server, navigation happens immediately and shows loading indicator, which looks good. But when it is already in cache, this is how the animation looks like. In any case have a beautiful day! https://user-images.githubusercontent.com/9447630/177713459-6e510665-a336-4b95-a173-f6a76a0445be.mp4

    opened by f3dm76 1
Owner
Lorenzo Fiamingo
Lorenzo Fiamingo
Cache - Nothing but Cache.

Cache doesn't claim to be unique in this area, but it's not another monster library that gives you a god's power. It does nothing but caching, but it does it well. It offers a good public API with out-of-box implementations and great customization possibilities. Cache utilizes Codable in Swift 4 to perform serialization.

HyperRedink 2.7k Dec 28, 2022
Apple Asset Cache (Content Cache) Tools

AssetCacheTool A library and tool for interacting with both the local and remote asset caches. This is based on research I did a few years ago on the

Kenneth Endfinger 21 Jan 5, 2023
CachyKit - A Caching Library is written in Swift that can cache JSON, Image, Zip or AnyObject with expiry date/TTYL and force refresh.

Nice threadsafe expirable cache management that can cache any object. Supports fetching from server, single object expire date, UIImageView loading etc.

Sadman Samee 122 Dec 28, 2022
Cachyr A typesafe key-value data cache for iOS, macOS, tvOS and watchOS written in Swift.

Cachyr A typesafe key-value data cache for iOS, macOS, tvOS and watchOS written in Swift. There already exists plenty of cache solutions, so why creat

Norsk rikskringkasting (NRK) 124 Nov 24, 2022
Carlos - A simple but flexible cache, written in Swift for iOS 13+ and WatchOS 6 apps.

Carlos A simple but flexible cache, written in Swift for iOS 13+ and WatchOS 6 apps. Breaking Changes Carlos 1.0.0 has been migrated from PiedPiper de

National Media & Tech 628 Dec 3, 2022
MemoryCache - type-safe, thread-safe memory cache class in Swift

MemoryCache is a memory cache class in swift. The MemoryCache class incorporates LRU policies, which ensure that a cache doesn’t

Yusuke Morishita 74 Nov 24, 2022
A lightweight generic cache for iOS written in Swift with extra love for images.

Haneke is a lightweight generic cache for iOS and tvOS written in Swift 4. It's designed to be super-simple to use. Here's how you would initalize a J

Haneke 5.2k Dec 29, 2022
High performance cache framework for iOS.

YYCache High performance cache framework for iOS. (It's a component of YYKit) Performance You may download and compile the latest version of sqlite an

null 2.3k Dec 16, 2022
Everyone tries to implement a cache at some point in their iOS app’s lifecycle, and this is ours.

Everyone tries to implement a cache at some point in their app’s lifecycle, and this is ours. This is a library that allows people to cache NSData wit

Spotify 1.2k Dec 28, 2022
Track is a thread safe cache write by Swift. Composed of DiskCache and MemoryCache which support LRU.

Track is a thread safe cache write by Swift. Composed of DiskCache and MemoryCache which support LRU. Features Thread safe: Implement by dispatch_sema

Cheer 268 Nov 21, 2022
UITableView cell cache that cures scroll-lags on cell instantiating

UITableView + Cache https://github.com/Kilograpp/UITableView-Cache UITableView cell cache that cures scroll-lags on a cell instantiating. Introduction

null 73 Aug 6, 2021
Fast, non-deadlocking parallel object cache for iOS, tvOS and OS X

PINCache Fast, non-deadlocking parallel object cache for iOS and OS X. PINCache is a fork of TMCache re-architected to fix issues with deadlocking cau

Pinterest 2.6k Dec 28, 2022
πŸ’Ύ Simple memory & disk cache

Cache ?? Simple memory & disk cache Usage ??‍?? Default let cache = Cache<String>() try memory.save("MyValue", forKey: "MyKey") let cached = try cac

SeongHo Hong 2 Feb 28, 2022
Cache library for videos for React Native

@lowkey/react-native-cache Cache everything Installation npm install @lowkey/react-native-cache Usage import ReactNativeCache from "@lowkey/react-nati

Max Prokopenko 1 Oct 1, 2021
🏈 Cache CocoaPods for faster rebuild and indexing Xcode project.

Motivation Working on a project with a huge amount of pods I had some troubles: - Slow and unnecessary indexing of pods targets, which implementation

Vyacheslav Khorkov 487 Jan 5, 2023
XCRemoteCache is a remote cache tool for Xcode projects.

XCRemoteCache is a remote cache tool for Xcode projects. It reuses target artifacts generated on a remote machine, served from a simple REST server. H

Spotify 737 Dec 27, 2022
A simple cache that can hold anything, including Swift items

CacheIsKing CacheIsKing is a simple cache that allows you to store any item, including objects, pure Swift structs, enums (with associated values), et

Christopher Luu 13 Jan 22, 2018
A simple but flexible cache

Carlos A simple but flexible cache, written in Swift for iOS 13+ and WatchOS 6 apps. Breaking Changes Carlos 1.0.0 has been migrated from PiedPiper de

National Media & Tech 628 Dec 3, 2022
MrCode is a simple GitHub iPhone App that can cache Markdown content (include images in HTML) for read it later.

MrCode is a simple GitHub iPhone App that can cache Markdown content (include images in HTML) for read it later.

hao 448 Dec 19, 2022