Swift: asynchronously loading and displaying photos

前端 未结 2 1653
南旧
南旧 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:33

    Have you looked into SDWebImage? It has built in cache support so that the device doesn't have to download images it has previously downloaded every single time. It also has the benefit of being very simple to implement!

    0 讨论(0)
  • 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<PHAsset> = 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)
        }
    }
    
    0 讨论(0)
提交回复
热议问题