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
}
至于底層原理是為什么,我也不清楚,只是根據報錯信息,蒙著改了。如果有了解這塊的朋友,歡迎大家留言討論。