Q:
iOS18 发布之后,收到了很多拉起相册时的崩溃客诉。堆栈日志如下:
#0 Thread
NSInternalInconsistencyException
opportunisticDegradedImagesToReturn cannot be zero.
解析原始
0
CoreFoundation
___exceptionPreprocess + 164
6
Photos
-[PHImageManager requestImageForAsset:targetSize:contentMode:options:resultHandler:] + 172
......(略)
crash 位置还是很清晰的,但是原因不清晰啊,没见过这个报错,网上也没搜到有效信息,也没听说 iOS18 后,相册哪里要做额外的兼容。
我们项目中的这块代码实现,简略如下:
PHImageRequestOptions *imageRequestOptions = [[PHImageRequestOptions alloc] initWithImageRequestOptions:options];
imageRequestOptions.synchronous = YES;
imageRequestOptions.networkAccessAllowed = YES;
imageRequestOptions.resizeMode = PHImageRequestOptionsResizeModeFast;
imageRequestOptions.deliveryMode = PHImageRequestOptionsDeliveryModeOpportunistic;
[[PHImageManager defaultManager] requestImageForAsset:phAsset targetSize:targetSize contentMode:PHImageContentModeAspectFit options:imageRequestOptions resultHandler:^(UIImage * _Nullable result, NSDictionary * _Nullable info) {
// TODO: image something
}];
A:
从报错信息看,主要是说 opportunisticDegradedImages
这个东西,不能是 zero,那 opportunistic 和 degraded 这两个关键词是什么意思呢?
opportunistic:
指的是 PHImageRequestOptions
对象 deliveryMode
属性的值,他表示请求的图像质量和交付优先级。我用的默认值 PHImageRequestOptionsDeliveryModeOpportunistic
,表示平衡下图像质量和响应速度,也就是报错这个关键词。详情可参考这篇文章:链接
@property (nonatomic, assign) PHImageRequestOptionsDeliveryMode deliveryMode; // delivery mode. Defaults to PHImageRequestOptionsDeliveryModeOpportunistic
typedef NS_ENUM(NSInteger, PHImageRequestOptionsDeliveryMode) {
PHImageRequestOptionsDeliveryModeOpportunistic = 0, // client may get several image results when the call is asynchronous or will get one result when the call is synchronous
PHImageRequestOptionsDeliveryModeHighQualityFormat = 1, // client will get one result only and it will be as asked or better than asked
PHImageRequestOptionsDeliveryModeFastFormat = 2 // client will get one result only and it may be degraded
};
degraded:
这单词是降级的意思,翻了翻 PHImageRequestOptions
的 API,allowSecondaryDegradedImage
属性看起来比较接近,他表示除了初始的降级结果之外,如果条件允许,是否还返回一个额外的降级结果。
这是 iOS17 新增的 API,官方也并没太多的说明介绍 AppleDevelopDoc链接
@property (nonatomic) BOOL allowSecondaryDegradedImage API_AVAILABLE(macos(14), ios(17), tvos(17)); // in addition to the initial degraded result, an additional degraded result will be returned if conditions permit
fix 方案:
于是尝试把 allowSecondaryDegradedImage
设为 YES 看看,然后就 OK 了。。。就不崩了。。。。
if (@available(iOS 17, *)) {
imageRequestOptions.allowSecondaryDegradedImage = YES;
} else {
// Fallback on earlier versions
}
至于底层原理是为什么,我也不清楚,只是根据报错信息,蒙着改了。如果有了解这块的朋友,欢迎大家留言讨论。