如何使用更少的内存在 collectionView 中显示照片库
Posted
技术标签:
【中文标题】如何使用更少的内存在 collectionView 中显示照片库【英文标题】:How to display photo library in collectionView using less memory 【发布时间】:2018-10-20 20:02:05 【问题描述】:我面临的问题是人们说在 collectionView 中加载照片库时应用程序崩溃。大多数时候,他们有超过 2-3 千张照片。对我来说它工作正常。 (我的图库中只有不到 1000 张照片)。
问题:也许有什么方法可以在 collectionView 中显示图像更“智能”并使用更少的内存?
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()
【问题讨论】:
这当然不是答案,但我相信UICollectionView
的工作方式与 UITableView
完全相同 - 也就是说,您不是与数千人一起工作的细胞。这些控件被构建为通过对它们的单元进行排队来尽可能少地使用内存。我想知道你的问题是否出在其他地方。也许你是如何退休/存储你的数据源的?
虽然与问题无关,但每次在self.imageArray
中添加新项目时停止重新加载集合视图。只需在循环完成时重新加载集合视图。它不会对实时图像显示做任何事情,因为主队列正忙于准备图像数组。
【参考方案1】:
问题出在这一行:
self.imageArray.append(image!)
切勿制作图像数组。图片很大,你会用完内存。
这是一个集合视图。您只需在 itemForRowAt:
中按需提供图像,您提供的是图像的 small 版本(即所谓的 thumbnail),对于显示屏尺寸。因此,任何时候都只有足够的缩略图来填满可视屏幕;这不会占用太多内存,而且运行时可以在图像滚出屏幕时释放图像内存。
这就是 PHCachingImageManager 的用途。仔细看看 Apple 在他们的示例代码中是如何处理这个问题的:
https://developer.apple.com/library/archive/samplecode/UsingPhotosFramework/Listings/Shared_AssetGridViewController_swift.html
在该示例中任何地方都没有图像数组。
【讨论】:
这是一个很好的解决方案。当大约有 1000 张照片时,从 80 mb 下降到 10 mb :) 无论如何,我不知道这可能是我的错,也可能不是,但是使用这段代码,所选择的图像的质量并不是那么好。 (没有太大区别,但仍然)。无论如何,谢谢! @matt 很棒的参考伙伴。尽管当我高速向下滚动图像的 collectionView 网格或滚动大量图像(比如 700)时,在某些时候应用程序由于内存问题而终止。对此有什么想法吗? T.I.A @HudiIlfeld 听起来您正在保留收到的图像。不要那样做。正如我在回答中所说,您应该保留的唯一图像是在任何给定时刻实际显示在集合视图中的缩略图(小)图像。 Apple 提供了出色的 WWDC 视频,介绍如何确保不会缓存不需要缓存的图像。【参考方案2】:在 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
【讨论】:
以上是关于如何使用更少的内存在 collectionView 中显示照片库的主要内容,如果未能解决你的问题,请参考以下文章