Swift: asynchronously loading and displaying photos

前端 未结 2 1654
南旧
南旧 2020-12-15 15:07

I\'m struggling with the problem of displaying photo gallery from iPhone to collectionView.

Everything works fine if someone has 50 photos inside t

2条回答
  •  攒了一身酷
    2020-12-15 15:35

    What you need is to add a fetchResult property to your collection view controller and fetch your image Assets inside viewDidLoad method.

    var fetchResult: PHFetchResult = PHFetchResult()
    
    func fetchAssets() {
        let fetchOptions = PHFetchOptions()
        fetchOptions.sortDescriptors = [NSSortDescriptor(key: "creationDate", ascending: false)]
        fetchResult = PHAsset.fetchAssets(with: .image, options: fetchOptions)
    }
    
    override func viewDidLoad() {
        super.viewDidLoad()
        fetchAssets()
    }
    

    Next step is extend UIImageView to request the image data asynchronously setting its image on completion.

    extension UIImageView {    
        func fetchImage(asset: PHAsset, contentMode: PHImageContentMode, targetSize: CGSize, version:  PHImageRequestOptionsVersion = .current, deliveryMode: PHImageRequestOptionsDeliveryMode = .opportunistic) {
            let options = PHImageRequestOptions()
            options.version = version
            options.deliveryMode = deliveryMode
            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
                @unknown default: fatalError()
                }
                self.image = image
            }
        }
    }
    

    Now you can fetch the images one at a time inside collection view cellForItemAt method:

    override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: reuseIdentifier, for: indexPath) as! CollectionViewCell
        let asset = fetchResult.object(at: indexPath.row)
        cell.imageView.fetchImage(asset: asset, contentMode: .aspectFill, targetSize: cell.imageView.frame.size * UIScreen.main.scale )
        return cell
    }
    

    Don't forget to return the fetchResult count for numberOfItemsInSection method.

    override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return fetchResult.count
    }
    

    class CollectionViewCell: UICollectionViewCell {
        @IBOutlet weak var imageView: UIImageView!
    }
    

    extension CGSize {
        static func *(lhs: CGSize, rhs: CGFloat) -> CGSize {
            .init(width: lhs.width * rhs, height: lhs.height * rhs)
        }
    }
    

提交回复
热议问题