iOS 15下全照片权限导致PHImageManager获取缩略图问题
问题:iOS 15下「所有照片」权限获取图片返回缩略图,「选中照片」则正常
当应用被授予「选中照片」权限时,以下代码能获取到预期的最大尺寸图片;但切换为「所有照片」权限后,返回的却是原图的缩略图。应用运行在iOS 15系统,未配置iCloud。
private func loadImage(assetId: String, done: @escaping (Image?) -> Void) { let fetchResults: PHFetchResult<PHAsset> = PHAsset.fetchAssets(withLocalIdentifiers: [assetId], options: nil) guard let asset: PHAsset = fetchResults.firstObject else { return } let manager = PHImageManager() manager.requestImage(for: asset, targetSize: PHImageManagerMaximumSize, contentMode: .aspectFit, options: nil) { (uiImage, _) in if let uiImage = uiImage { done(Image(uiImage: uiImage)) } else { done(nil) } } }
原因分析
问题出在PHImageManager.requestImage的默认行为差异上:
- 「选中照片」权限下,你指定的资产通常是本地直接可访问的,Photos框架能快速返回高清原图,不会触发占位图逻辑
- 「所有照片」权限下,Photos框架默认会优先返回低分辨率缩略图作为快速占位,再异步加载高清图,但你的代码没有处理这种分阶段回调,只拿到了第一帧的缩略图
解决方案
通过配置PHImageRequestOptions强制获取高质量图片,同时处理可能的分阶段回调:
- 创建
PHImageRequestOptions实例,设置deliveryMode为.highQualityFormat,跳过占位图直接加载高清图 - 可选设置
resizeMode配合PHImageManagerMaximumSize确保获取原图尺寸 - 监听
info字典中的PHImageResultIsDegradedKey,忽略临时缩略图回调,只处理最终高清图
修改后的代码如下:
private func loadImage(assetId: String, done: @escaping (Image?) -> Void) { let fetchResults: PHFetchResult<PHAsset> = PHAsset.fetchAssets(withLocalIdentifiers: [assetId], options: nil) guard let asset = fetchResults.firstObject else { done(nil) return } let options = PHImageRequestOptions() // 强制只返回高质量图片,不返回占位缩略图 options.deliveryMode = .highQualityFormat // 配合目标尺寸获取精确的原图大小 options.resizeMode = .exact let manager = PHImageManager() manager.requestImage(for: asset, targetSize: PHImageManagerMaximumSize, contentMode: .aspectFit, options: options) { (uiImage, info) in // 过滤低质量的临时回调 guard let isDegraded = info?[PHImageResultIsDegradedKey] as? Bool, !isDegraded else { return } done(uiImage.map { Image(uiImage: $0) }) } }
如果需要保留占位图优化体验,可以将deliveryMode设为默认的.opportunistic,通过PHImageResultIsDegradedKey区分临时和最终回调,先显示缩略图再替换为高清图。
内容的提问来源于stack exchange,提问作者Macs
相关产品推荐
相关产品推荐

