Search code examples
swiftcollectionview

swift 4, how do I load over 3000~ pictures in collectionView?


I am using UICollectionView for an album. I got the picture to load on iPhone 7. I got it to load about 2000 pictures but if there are over 3000 pictures when I scroll the UICollectionView down it is very slow and some times the app stops.

I am using this code to get the pictures.

extension UIImageView {
    func fetchImage(asset: PHAsset, contentMode: PHImageContentMode, targetSize: CGSize) {
        let options = PHImageRequestOptions()
        options.version = .original
        options.isSynchronous = true
        PHImageManager.default().requestImage(for: asset, targetSize: targetSize, contentMode: contentMode, options: options) { image, _ in
            guard let image = image else { return }
            switch contentMode {
            case .aspectFill:
                self.contentMode = .scaleAspectFill
            case .aspectFit:
                self.contentMode = .scaleAspectFit
            }
            self.image = image
        }
    }
}

and I made a let imageCache = NSCache<NSIndexPath, UIImage>() and used it in the cellForItem. but that didn't help this problem. is there any other way to do this?

and also I am getting 3 picture a row and the size of self.view.frame.width / 2

If there is no way. Do I have to get a smaller size of the image?

cellForItem code:

let imageCache = NSCache<NSIndexPath, UIImage>()

override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {

    let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "albumCell", for: indexPath) as? AlbumCollectionViewCell

    let asset: PHAsset? = AlbumModel.allPhotos?.object(at: indexPath.row)

    cell!.albumImageView.contentMode = .scaleAspectFill
    if let fromImageCache = imageCache.object(forKey: indexPath as NSIndexPath) {
        cell!.albumImageView.image = fromImageCache
        return cell!
    }

    let setSize = CGSize(width: view.frame.width / 2, height: view.frame.width / 2)
    cell!.albumImageView.fetchImage(asset: asset!, contentMode: .aspectFill, targetSize: setSize)

    imageCache.setObject(cell!.albumImageView.image!, forKey: indexPath as NSIndexPath)
    return cell!
}

Solution

  • Here are some tips to improve performance when scrolling through the photo library:

    Don't implement your own image cache or use the default image manager, use your own instance of PHCachingImageManager. You can tell it to start caching images surrounding your scroll position to improve performance.

    Don't use synchronous fetching of images. Use the asynchronous methods and update the image view in the completion block, though note that the completion block can fire before the fetch method has even returned, and fire multiple times as you get better quality images out of the library.

    Cancel fetches as your cells go off screen.

    I haven't worked with the framework for a while, but I wrote up some notes about it here which are hopefully still relevant.