retrieveImage() shows wrong image if used in a quickly scrolling list view?
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()?
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.
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.
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.