Swift 3: Caching images in a collectionView


December 2018


2k time


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 UIImageViews aren't being populated when the image is fetched.

Here is the code (in the ...cellForItemAt... function):

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 prints to find out what is going on. When the view loads, I can see cache misses, and the images loading and the UIImageViews being populated for the visible rows, however when I scroll down, the UIImageViews are never populated, and the log shows CELL NOT FOUND: [0, x] 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!


1 answers


Вместо того , чтобы получать клетки с помощью cellForItem(at: indexPath)метода, просто использовать cellпеременную , которую вы используете для установки изображения в хит кэша. Это позволит создать сильную ссылку , чтобы просмотреть изображение клетки.

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

Рассмотрим переименование UIImageViewдо , imageViewа не image.