0

When I delete the data from array, the operation is successful, but only the picture does not change. The image still remains in the cache. However, when I close and open the application, the application works fine. how can i update the cache?

enter image description here

Image Loader

import Combine

class ImageLoader: ObservableObject {
    @Published var image: UIImage?
    private let url: String
    private var cancellable: AnyCancellable?
    private var cache: ImageCache?
    
    init(url: String, cache: ImageCache? = nil) {
        self.url = url
        self.cache = cache
    }
    
    deinit {
        cancel()
    }
    
    func load() {
        
        guard let cacheURL = URL(string: url) else { return }
        if let image = cache?[cacheURL] {
            self.image = image
            return
        }
        
        guard let url = URL(string: url) else { return }
        
        cancellable = URLSession.shared.dataTaskPublisher(for: url)
            .map { UIImage(data: $0.data) }
            .replaceError(with: nil)
            .handleEvents(receiveOutput: { [weak self] in self?.cache($0) })
            .receive(on: DispatchQueue.main)
            .sink { [weak self] in self?.image = $0 }
    }
    
    private func cache(_ image: UIImage?) {
        guard let cacheURL = URL(string: url) else { return }
        image.map { cache?[cacheURL] = $0 }
    }
    
    func cancel() {
        cancellable?.cancel()
    }
}

Async Image

import Combine

struct AsyncImage<Placeholder: View>: View {
    @StateObject private var loader: ImageLoader
    private let placeholder: Placeholder
    
    init(url: String, @ViewBuilder placeholder: () -> Placeholder) {
        self.placeholder = placeholder()
        _loader = StateObject(wrappedValue: ImageLoader(url: url, cache: Environment(\.imageCache).wrappedValue))
    }
    
    var body: some View {
        content
            .onAppear(perform: loader.load)
    }
    
    private var content: some View {
        Group {
            if loader.image != nil {
                Image(uiImage: loader.image!)
                    .resizable()
            } else {
                placeholder
            }
        }
    }
}

Image Cache

protocol ImageCache {
    subscript(_ url: URL) -> UIImage? { get set }
}

Temporary Image Cache

struct TemporaryImageCache: ImageCache {
    private let cache = NSCache<NSURL, UIImage>()
    
    subscript(_ key: URL) -> UIImage? {
        get { cache.object(forKey: key as NSURL) }
        set { newValue == nil ? cache.removeObject(forKey: key as NSURL) : cache.setObject(newValue!, forKey: key as NSURL) }
    }
}

Image Cache Key

struct ImageCacheKey: EnvironmentKey {
    static let defaultValue: ImageCache = TemporaryImageCache()
}

extension EnvironmentValues {
    var imageCache: ImageCache {
        get { self[ImageCacheKey.self] }
        set { self[ImageCacheKey.self] = newValue }
    }
}

Async Image Using

 VStack {
      ZStack(alignment: .bottomTrailing) {
                
           AsyncImage(url: "image url") {
                Text("Loading")
            }
             .aspectRatio(contentMode: .fill)
             .frame(width: 120, height: 180, alignment: .center)
             .cornerRadius(15)
           ....
      }
}
Ufuk Köşker
  • 1,288
  • 8
  • 29
  • 1
    Could you show your removal method? – NicolasElPapu Apr 08 '21 at 12:13
  • 2
    None of the code you showed actually shows how you render multiple images and the code to remove. Why do you think it has to do with caching? Your cache key is a URL - you might be passing the wrong URL into the `AsyncImage` – New Dev Apr 08 '21 at 13:00

0 Answers0