kean / Nuke

Image loading system
https://kean.blog/nuke
MIT License
8.07k stars 528 forks source link

Custom DataLoader without native URL cache #781

Open alexacz opened 4 months ago

alexacz commented 4 months ago

I'm trying to implement a custom plugin. I download SVG data from URL, then I generate png image from SVG. I don't want to cache SVG data (URL cache), I would cache png image, I would use LRU disk cache only for that. My question is: How to implement custom DataLoader without native URL cache but with LRU disk cache?

Below is my current implementation. The issue: data is caching to memory only even if I have configured the LRU cache in my custom ImagePipeline.

public final class SvgDataLoader: Nuke.DataLoading {
  ...
  public func loadData(with request: URLRequest,
    didReceiveData: @escaping (Data, URLResponse) -> Void,
    completion: @escaping (Error?) -> Void) -> Nuke.Cancellable {
      // download svg, convert to png
      ...
      didReceiveData(pngData, URLResponse(url: request.url!,
        mimeType: "image/png",
        expectedContentLength: pngData.count,
        textEncodingName: "utf8"))
      ...
 }
}
let customPipeline = ImagePipeline {
    let dataCache = try? DataCache(name: "com.qazwsxedcrfv.datacache")
    dataCache?.sizeLimit =  100 * 1024 * 1024    // 100 MiB
    dataCache?.sweepInterval = 3600 * 24 * 180   // 180 days
    $0.dataCache = dataCache
    $0.dataLoader = SvgDataLoader()
}
...
LazyImage(request:request) { state in
    if let image = state.image {
        image.resizable().scaledToFit().padding(10)
    } else if state.error != nil {
        Color(.systemBackground)
            .frame(minWidth: 140, minHeight: 100)
            .overlay{
                Image(systemName: "exclamationmark.octagon").font(.body)
            }
    } else {
        Color(.systemBackground)
            .frame(minWidth: 140, minHeight: 100)
            .overlay(ProgressView())
    }
}
.pipeline(customPipeline)
...
kean commented 4 months ago

Hey,

I would suggest trying DataCachePolicy.storeEncodedImages. It will encode the processed images (.png) and stored them in the disk cache (aka LRU cache, DataCache). It seems like exactly what you are looking for.