6

I am using Kingfisher library for the purpose of caching images in UICollectionView cells.

I noticed that calling kf_setImage (assuming that the name of the cell called listCell and its ImageView called imgMain) as follows:

listCell.imgMain.kf.setImage(with: URL(string: "MY IMAGE URL"),
                             placeholder: UIImage(named: "PLACEHOLDER IMAGE"))

works fine, it does caches the image and display it when cell has been re-dequeued (when scrolling up and down, I can see the image directly without re-downloading it), but when I pull to refresh the collection view (recall the API with the same exact parameters, which means that it will return the same image urls) the images have been re-downloaded! I assume that the images already have been cached.

To make it more clear, this link contains gif image that describes what am I facing.

So, why the images get downloaded once again? is it the default behavior of the caching in Kingfisher? Is there any configuration that should edited to behave as I expect?

I read the library documentation, but -unfortunately- I couldn't find and useful information related to what am I asking for.

Ahmad F
  • 30,560
  • 17
  • 97
  • 143

2 Answers2

14

Kingfisher is using the whole url as the cache key by default, so you have to ensure that you have the very SAME url string for the images every time you request your API. If there is something like timestamp or version number appended to the urls, the cache will fail. (eg. http://example.com/image.png?time=123 and http://example.com/image.png?time=456 will be recognized as two different cache keys, although you could get the same image from it).

This is the only case I could draw for your operation. If this is true for you, you could create an ImageResource to specify the cache key explicitly (which should be related to your original url, but get rid of the appended things):

let r = ImageResource(downloadURL: yourUrl, cacheKey: key)
imageView.kf.setImage(with: r, placeholder: yourImage)
onevcat
  • 4,591
  • 1
  • 25
  • 31
  • Thank you for your consideration. That's exactly what I faced, the URL parameters are different when calling the API for the next time. As you mentioned in your code snippet, using `ImageResource` solved my problem . – Ahmad F Mar 28 '17 at 08:11
  • Just to make sure that I got it right, `ImageResource` works as: if the key is *not* `nil` it should will recognize the existing image even if the url has been changed, is that right? – Ahmad F Mar 28 '17 at 09:58
  • Yes you are right on this. By default the key would be the absolute string of your url. Once you set it by yourself, the input key will be respected and used to search in the cache. – onevcat Mar 30 '17 at 04:47
1

According to the behaviour of Kingfisher I saw before for the loading of the cells initially is getting the images and saving to a cache.

Every time you scroll it handle it the change of image, reload, getting from the cache, etc. In your Pull to refresh you're reloading your data source, so Kingfisher would try to reload the cache again, of course, you can avoid it handling the cache manually yourself with Kingfisher or specifying in the options of the kf_setImage method.

If see the signature of the method kf_setImage:

public func kf_setImage(with resource: Resource?,
                          placeholder: Image? = nil,
                              options: KingfisherOptionsInfo? = nil,
                        progressBlock: DownloadProgressBlock? = nil,
                    completionHandler: CompletionHandler? = nil) -> RetrieveImageTask

It has the options parameter nil by default. You can specify in these parameters like the onlyFromCache and if set, Kingfisher will only try to retrieve the image from the cache, not from the network.

imageView.kf.setImage(with: url, options: [.onlyFromCache])

The another way if customising the ImageCache and ImageDownloader to your requirements.

But you need to be careful because when you do a Pull to Refresh the default behaviour should be shown first the images from the cache and update it as it comes from the network, so you need to handle it in some way like this.

I hope this help you

Victor Sigler
  • 23,243
  • 14
  • 88
  • 105
  • Thank you for your answer. For the first app launching, If `options` is set to `onlyFromCache` it won't get any data, I assume that because there is no cached data yet. – Ahmad F Mar 27 '17 at 15:24
  • @AhmadF Yes of course!!! , remember with Kingfisher you can specify the duration of the cache, size, etc. So my point is you can save your images and persist it by the period you want – Victor Sigler Mar 27 '17 at 15:26
  • 1
    So, there is no option for: downloading (caching) the image for the first time (if not exist) and use it for the next time (if exist)... doing such a functionality manually is kind of confusing to me, not because I'm not that smart, but I assume it should be exist :) – Ahmad F Mar 27 '17 at 15:36
  • 1
    To handle that I'm afraid you should use the [`ImageCache`](https://github.com/onevcat/Kingfisher/wiki/Cheat-Sheet#use-imagecache-to-store-or-get-images) yourself – Victor Sigler Mar 27 '17 at 15:49