1

Background of problem: I am using Kingfisher to download and set images for all of my collection views and table views in my app. This works well, but I have one specific use case that I'm pretty sure Kingfisher doesn't have built in.

What I am trying to do: Download multiple images for a single collection view cell, and then update the cell with the images.

Why I am not using .kf.setImage(...): The collection view cell UI is all drawn from draw(_ rect: CGRect)

What I am doing now: In my UICollectionViewCell I have an image array

var posters: [UIImage] = [] {
    didSet {
        setNeedsDisplay()
    }
}

and I draw them into the cell

context.draw(image, in: CGRect(x: 0, y: -posterWindowFrame.minY, width: actualPosterWidth, height: actualPosterHeight))

In my view controller I load images in willDisplayCell:forItemAtIndexPath: like so

override func collectionView(_ collectionView: UICollectionView, willDisplay cell: UICollectionViewCell, forItemAt indexPath: IndexPath) {
        let imageProviders = viewModel.imageProviders(at: indexPath)
        var images = [UIImage]()
        let group = DispatchGroup()
        let cachedIndexPath = indexPath
        imageProviders.forEach { provider in
            guard let provider = provider else { return }
            group.enter()
            _ = KingfisherManager.shared.retrieveImage(with: .provider(provider), options: [.targetCache(posterCache)]) { result in
                DispatchQueue.main.async {
                    defer {
                        group.leave()
                    }
                    switch result {
                    case .success(let imageResult):
                        images.append(imageResult.image)
                    case .failure:
                        print("No image available")
                    }
                }
            }
        }

        group.notify(queue: .main) {
            guard
                let cell = collectionView.cellForItem(at: cachedIndexPath) as? ListCollectionViewCell
                else { return }
            cell.posters = images
        }
    }

This works, but I can see the images changing (which could probably be fixed by pre-fetching) but I also notice a lot of lag when scrolling that I don't see when I comment this function out.

Besides fetching all of the images in ViewDidLoad (or anywhere else, because of API rate limiting), how can I load these images in a way that doesn't cause lag and won't have problems with cell reuse?

EDIT - 8/13/19 I used UICollectionViewDataSourcePrefetching to fetch the images and cache them locally, and then set the images in cellForRow and it seems to work well for now.

Maximilian Litteral
  • 3,059
  • 2
  • 31
  • 41

0 Answers0