我的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:只加载与图像关联的单元格。