Kingfisher icon indicating copy to clipboard operation
Kingfisher copied to clipboard

retrieveImage() shows wrong image if used in a quickly scrolling list view?

Open waterdrake opened this issue 2 years ago • 3 comments

I noticed that when using KingfisherManager.shared.retrieveImage() in a list collection view to get the image and set it in a cell, the wrong image might be shown when scrolling quickly. Is there some sort of race condition or threading issue that happens when using retrieveImage() as opposed to imageView.kf.setImage()?

waterdrake avatar Apr 29 '23 21:04 waterdrake

Different from the extension method (imageView.kf.setImage()) which can keep track of your view and determine which image is for which cell (even it is reused), the manager method retrieveImage does not (and do not have the capability to) do that for you. It just hears your order and gets the image. So if you are reusing your cells, it just initializes another retrieving with the previous ones still running.

So you need to invent a mechanism yourself for that purpose, to cancel a previous task or only set the last image to the cell.

It is quite unusual that you ever need the retrieveImage in the view layer. If I can know your use case, maybe there is a better way to do.

onevcat avatar May 01 '23 00:05 onevcat

The use case is to download an image, calculate its dimensions (which we do not know until we download the image) and then update the scale type of the image view based on those dimensions.

waterdrake avatar May 06 '23 03:05 waterdrake

Then I would suggest you bind a task to your cell, and always try to cancel the task if another download starts:

class ImageCollectionViewCell: UICollectionViewCell {
    
    var task: Kingfisher.DownloadTask?
    
    func setData(url: URL) {
        task?.cancel()
        task = KingfisherManager.shared.retrieveImage(with: url) { result in
            switch result {
            case .success(let r):
                print(r.image.size)
                // Update your image view size.
            case .failure:
                print("error, maybe cancelled.")
            }
        }
    }
}

This should prevent multiple invocations even you reuse the cell and starts multiple downloads.

onevcat avatar May 18 '23 14:05 onevcat