如何使用更少的内存在 collectionView 中显示照片库

How to display photo library in collectionView using less memory

我遇到了一个问题,人们说在 collectionView 中加载照片库时应用程序崩溃。大多数时候他们有超过 2-3 千张照片。对我来说它工作正常。 (我的图库中只有不到 1000 张照片)。

问题:有没有什么方法可以让collectionView中的图片显示得更多"smart"并且使用更少的内存?

P.S 也许当用户在 iCloud 中拥有他的所有照片时也会导致崩溃?因为直到现在我还认为应用程序在将照片加载到单元格中时并未下载照片。也许有人可以证明或不赞成这个事实。

这是我的函数:

func grabPhotos(){

    let imgManager = PHImageManager.default()

    let requestOptions = PHImageRequestOptions()
    requestOptions.isSynchronous = false
    requestOptions.deliveryMode = .opportunistic // Quality of images
    requestOptions.isNetworkAccessAllowed = true

    requestOptions.isSynchronous = true
    requestOptions.progressHandler = {  (progress, error, stop, info) in
        print("progress: \(progress)")
    }

    let fetchOptions = PHFetchOptions()
    fetchOptions.sortDescriptors = [NSSortDescriptor(key: "creationDate", ascending: false)]

    if let fetchResult : PHFetchResult = PHAsset.fetchAssets(with: .image, options: fetchOptions) {

        if fetchResult.count > 0 {
            for i in 0..<fetchResult.count {
                imgManager.requestImage(for: fetchResult.object(at: i) , targetSize: CGSize(width: 150, height: 150), contentMode: .aspectFill, options: requestOptions, resultHandler: { image, error in
                    self.imageArray.append(image!)
                    self.kolekcija.reloadData()
                })
            }
        }
        else {
            print("You got no photos")
            kolekcija.reloadData()
        }
    }

}

问题出在这一行:

self.imageArray.append(image!)

切勿制作图片数组。图片很大,你会 运行 内存不足。

这是一个集合视图。您只需按需在 itemForRowAt: 中提供图像,而您提供的是图像的 small 版本(所谓的 thumbnail), 显示尺寸的最小可能。因此,在任何时候,缩略图都只够填满可见屏幕;这不会占用太多内存,而且 运行时间可以在图像滚出屏幕时释放图像内存。

这就是 PHCachingImageManager 的用途。仔细查看 Apple 如何在示例代码中处理此问题:

https://developer.apple.com/library/archive/samplecode/UsingPhotosFramework/Listings/Shared_AssetGridViewController_swift.html

在该示例中 任何地方 都没有图像数组。

正在 Swift 5. 获取照片资产,但在 cellForItem 迭代之前不要加载照片。编码愉快。

    var personalImages: PHFetchResult<AnyObject>!
            
    func getPersonalPhotos() {
         let fetchOptions = PHFetchOptions()
         fetchOptions.sortDescriptors = [NSSortDescriptor(key: "creationDate", ascending: false)]
         self.personalImages = (PHAsset.fetchAssets(with: .image, options: fetchOptions) as AnyObject?) as! PHFetchResult<AnyObject>? 
            
         photoLibraryCollectionView.reloadData()
    }
        
    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        
         return personalImages.count
    }

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
    
    let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "insertCellIdentifierHere", for: indexPath) as! InsertACollectionViewCellHere
    
    let asset: PHAsset = self.personalImages[indexPath.item] as! PHAsset
    let itemWidth = photoLibraryCollectionView.frame.size.width / 2
    let itemSize = CGSize(width: itemWidth, height: itemWidth / 2) // adjust to your preferences
    
    PHImageManager.default().requestImage(for: asset, targetSize: itemSize, contentMode: .aspectFill, options: nil, resultHandler: {(result, info)in
        if result != nil {
            
            cell.photoImageView.image = result
        }
    })
    
    cell.layoutIfNeeded()
    cell.updateConstraintsIfNeeded()
    return cell
}