当我尝试在 UICollectionView 中显示用户的照片库时应用程序崩溃



我的ViewController看起来像:顶部是相机视图,底部是照片库,就像在Instagram中一样。

当我尝试加载用户的图像库并将其显示在UICollectionView上时,应用程序会因Memory Warning而崩溃。如何预防和改善我的功能?

我的功能:

func getImagesFromLibrary(from: Int = 0, to: Int = 5, completion: (loaded: Bool) -> Void) {
if images.count > 0 {
for i in from..<to {
let asset: PHAsset = self.images[i] as! PHAsset
let imageFetchOptions = PHImageRequestOptions()
self.imageManager.requestImageForAsset(asset, targetSize: CGSize(width: 75, height: 75), contentMode: .AspectFit, options: imageFetchOptions, resultHandler: { (image: UIImage?, info: [NSObject : AnyObject]?) in
if (image != nil) {
if let img = image {
self.croppedImagesArray[i] = img
self.imagesCollectionView.reloadData()
}
}
})
}
completion(loaded: true)
} else {
print("Images Empty")
}
}

我叫它通过:

if AVCaptureDevice.authorizationStatusForMediaType(AVMediaTypeVideo) ==  AVAuthorizationStatus.Authorized {
print("GRANTED")
self.getImagesFromLibrary { (loaded) in
if loaded {
print("Images Count: (self.images.count)")
if self.images.count > 5 {
print("Second part")
self.getImagesFromLibrary(5, to: self.images.count / 2, completion: { (loaded) in
if loaded {
self.getImagesFromLibrary(self.images.count / 2, to: self.images.count, completion: { (loaded) in })
}
})
}
}
}
}

所以,现在我的图库里有300张图片。这是很多,这就是为什么我的应用程序在加载过程中崩溃。

我该如何解决?有什么解决方案吗?

显然,您只是在内存中保存了太多图像,因此会收到内存警告
当您收到内存警告时,iOS会让您有机会发布易于重新创建的数据。如果你不这样做,你的应用程序可能随时被终止。

所以问题是,你是否真的需要把所有这些图像都保存在记忆中
如果是这样的话,你就遇到了真正的问题,iOS可能不是你的应用程序的合适平台
如果不是,例如,如果您想一次只显示部分加载的图像,则应使用在内存中没有应显示的图像时显示的占位符图像,下载图像,并在下载后立即用真实图像替换占位符。

存储图像以避免内存警告的一种方法是使用NSCache<Docs>,有点像NSMutableDictionary,可以在其中存储图像,但当内存紧张时,使用时间不长的图像将自动清除。因此,如果你必须显示图像,你可以首先显示占位符,然后尝试从缓存中加载它,如果失败,则下载它。
当然,也有一些框架可以自动为你进行缓存,例如AFNetworking<Github>。

默认情况下requestImageForAsset:是异步的。您编写的代码将立即触发对所有300个图像的请求,并且当您看到内存耗尽时。因此,加载5个图像的代码,然后是前半部分,然后是后半部分,都是一次性运行的。

我建议在UICollection cellForRowAtIndexPath中:调用self.imageManager.requestImageForAsset(self.images[indexPath.item]……并在结果处理程序块中为该单元格设置UImageView。无需预加载所有300个图像,用户甚至可能永远无法滚动查看所有图像。其他人可能有3000个或更多图像。

此外,在结果处理程序中,每次提取图像时调用collectionView reloadData,甚至在提取的图像当前未显示时重新加载。使用reloadItemsAtIndexPath:只加载与图像关联的单元格。

最新更新