Ben Ben - 1 month ago 17x
iOS Question

Swift 3: Caching images in a collectionView

I'm currently working through my app, updating it to work with Swift 3 and have one problem left. Previously, my image caching worked really well, but since the update the

s aren't being populated when the image is fetched.

Here is the code (in the

if let img = imageCache[imageUrl] {
print("CACHE HIT: \(indexPath)")
cell.image.image = img
} else {
print("CACHE MISS: \(indexPath)")
var imgUrl: = URL(string: imageUrl)
let request: URLRequest = URLRequest(url: imgUrl!)
let dataTask = session.dataTask(with: request, completionHandler: { (data, response, error) -> Void in
if(data != nil) {
print("IMAGE DOWNLOADED: \(imgUrl?.query))")
let image = UIImage(data: data!) // create the image from the data
self.imageCache[imageUrl] = image // Store in the cache
DispatchQueue.main.async(execute: {
if let cell = collectionView.cellForItem(at: indexPath) as? MyCollectionViewCell {
print("APPLYING IMAGE TO CELL: \(indexPath)")
cell.image.image = image
} else {
print("CELL NOT FOUND: \(indexPath)")

As you can see, I've added in some
s to find out what is going on. When the view loads, I can see cache misses, and the images loading and the
s being populated for the visible rows, however when I scroll down, the
s are never populated, and the log shows
for each indexPath.

If I scroll up again after scrolling down, images are populated from the cache as expected.

The code hasn't changed since the previous version of Swift / iOS / Xcode, and used to work perfectly.

I'm not interested in any 3rd party extensions etc.; I want to understand what is wrong with the code above. Any other improvements/suggestions to the code however are welcome.

Any ideas would be very much appreciated!


Rather than getting the cell via the cellForItem(at: indexPath) method, just use the cell variable you use to set the image in the cache hit. This will create a strong reference to the cell's image view.

DispatchQueue.main.async(execute: { [weak collectionView] in
    cell.image.image = image

Consider renaming your UIImageView to imageView rather than image.