iOS应用从PHAssets生成图片时因内存问题崩溃求助
解决PHAsset获取原图导致内存崩溃的问题
崩溃原因
- 手机相册中的照片多为高分辨率(比如4000×3000甚至更高),直接加载原始像素尺寸的图片会占用大量内存,批量加载时会瞬间耗尽应用可用内存,触发崩溃。
- 同步请求(
option.isSynchronous = true)会强制系统立即加载全尺寸图片,缺乏内存缓冲优化,进一步加剧内存压力。
解决方案
1. 按需加载适配尺寸的图片
不要直接使用self.pixelWidth/self.pixelHeight作为目标尺寸,根据实际显示场景设置合理大小,比如屏幕分辨率、控件显示尺寸,既满足需求又控制内存占用。
2. 改用异步请求加载图片
同步请求会阻塞线程且内存管理效率低,异步请求配合回调处理图片,系统会自动优化内存分配,避免批量加载导致的内存暴涨。
3. 优化批量加载逻辑
不要一次性将所有图片存入数组,建议在列表(UITableView/UICollectionView)滚动时,仅加载可见区域的图片;也可以使用PHCachingImageManager实现图片预加载与缓存,由系统自动管理内存。
修改后的代码示例
异步获取图片的PHAsset扩展
extension PHAsset { func getImage(targetSize: CGSize, completion: @escaping (UIImage?) -> Void) { let manager = PHImageManager.default() let options = PHImageRequestOptions() // 按需选择交付模式:追求速度用.fastFormat,追求质量用.highQualityFormat options.deliveryMode = .highQualityFormat // 允许访问iCloud中的图片(如果需要) options.isNetworkAccessAllowed = true manager.requestImage(for: self, targetSize: targetSize, contentMode: .aspectFit, options: options) { result, info in completion(result) } } }
异步批量加载相册截图
func fetchPhotos() { let fetchOptions = PHFetchOptions() fetchOptions.predicate = NSPredicate(format: "(mediaSubtype & %d) != 0", PHAssetMediaSubtype.photoScreenshot.rawValue) let fetchedResult = PHAsset.fetchAssets(with: .image, options: fetchOptions) // 设置目标尺寸为屏幕分辨率大小(适配显示需求) let screenScale = UIScreen.main.scale let targetSize = CGSize(width: UIScreen.main.bounds.width * screenScale, height: UIScreen.main.bounds.height * screenScale) for index in 0..<fetchedResult.count { let asset = fetchedResult.object(at: index) asset.getImage(targetSize: targetSize) { [weak self] image in guard let self = self, let image = image else { return } self.testImages.append(image) // 主线程更新UI(比如刷新列表) DispatchQueue.main.async { // self.yourCollectionView.reloadData() } } } }
额外注意事项
- 不要强制解包
result!,请求可能因网络、权限等原因失败,必须做可选绑定处理。 - 使用
[weak self]避免闭包导致的循环引用,防止内存泄漏。 - 如果确实需要加载原图,务必分批加载,并及时释放不再使用的图片对象,避免内存累积。
内容的提问来源于stack exchange,提问作者narner
相关产品推荐
相关产品推荐

