Len*_*enK 45 ios photosframework
大约10%的时间PHImageManager.defaultManager().requestImageForAsset在首次返回有效但"降级"的UIImage后返回nil而不是有效的UIImage.没有错误或其他线索,我可以看到返回信息与零.
这似乎发生在需要从iCloud下载的照片上,同时启用了iCloud Photo Library和Optimize iPad Storage.我已经尝试过更改选项,尺寸等,但似乎没什么关系.
如果我在失败后重试requestImageForAsset,它通常会正确返回一个UIImage,虽然有时需要重试几次.
知道我可能做错了什么吗?或者它只是Photos框架中的一个错误?
func photoImage(asset: PHAsset, size: CGSize, contentMode: UIViewContentMode, completionBlock:(image: UIImage, isPlaceholder: Bool) -> Void) -> PHImageRequestID? {
let options = PHImageRequestOptions()
options.networkAccessAllowed = true
options.version = .Current
options.deliveryMode = .Opportunistic
options.resizeMode = .Fast
let requestSize = !CGSizeEqualToSize(size, CGSizeZero) ? size : PHImageManagerMaximumSize
let requestContentMode = contentMode == .ScaleAspectFit ? PHImageContentMode.AspectFit : PHImageContentMode.AspectFill
return PHImageManager.defaultManager().requestImageForAsset(asset, targetSize: requestSize, contentMode: requestContentMode, options: options)
{ (image: UIImage!, info: [NSObject : AnyObject]!) in
if let image = image {
let degraded = info[PHImageResultIsDegradedKey] as? Bool ?? false
completionBlock(image: photoBlock.rotatedImage(image), isPlaceholder: degraded)
} else {
let error = info[PHImageErrorKey] as? NSError
NSLog("Nil image error = \(error?.localizedDescription)")
}
}
}
Run Code Online (Sandbox Code Playgroud)
ahb*_*bou 39
我也刚刚经历过这个.通过我的测试,问题出现在启用了"优化存储"选项的设备上,并且位于以下两种方法之间的差异:
[[PHImageManager defaultManager] requestImageForAsset:...]
如果您的选项配置正确,这将成功获取远程iCloud图像.
[[PHImageManager defaultManager] requestImageDataForAsset:...]
此功能仅适用于驻留在手机内存上的图像或最近由您的应用程序在任何其他内容上从iCloud中提取的图像.
这是我正在使用的一个工作片段 - 跟我一起玩Obj-c :)
PHImageRequestOptions *options = [[PHImageRequestOptions alloc] init];
options.deliveryMode = PHImageRequestOptionsDeliveryModeHighQualityFormat; //I only want the highest possible quality
options.synchronous = NO;
options.networkAccessAllowed = YES;
options.progressHandler = ^(double progress, NSError *error, BOOL *stop, NSDictionary *info) {
NSLog(@"%f", progress); //follow progress + update progress bar
};
[[PHImageManager defaultManager] requestImageForAsset:myPhAsset targetSize:self.view.frame.size contentMode:PHImageContentModeAspectFill options:options resultHandler:^(UIImage *image, NSDictionary *info) {
NSLog(@"reponse %@", info);
NSLog(@"got image %f %f", image.size.width, image.size.height);
}];
Run Code Online (Sandbox Code Playgroud)
针对Swift 4进行了更新:
let options = PHImageRequestOptions()
options.deliveryMode = PHImageRequestOptionsDeliveryMode.highQualityFormat
options.isSynchronous = false
options.isNetworkAccessAllowed = true
options.progressHandler = { (progress, error, stop, info) in
print("progress: \(progress)")
}
PHImageManager.default().requestImage(for: myPHAsset, targetSize: view.frame.size, contentMode: PHImageContentMode.aspectFill, options: options, resultHandler: {
(image, info) in
print("dict: \(String(describing: info))")
print("image size: \(String(describing: image?.size))")
})
Run Code Online (Sandbox Code Playgroud)
上述方法对我都不起作用,但这个解决方案却有效!
private func getUIImage(asset: PHAsset, retryAttempts: Int = 10) -> UIImage? {
var img: UIImage?
let manager = PHImageManager.default()
let options = PHImageRequestOptions()
options.version = .original
options.isSynchronous = true
options.isNetworkAccessAllowed = true
manager.requestImage(for: asset, targetSize: CGSize(width: asset.pixelWidth, height: asset.pixelHeight), contentMode: .aspectFit, options: options, resultHandler: { image, _ in
img = image
})
if img == nil && retryAttempts > 0 {
return getUIImage(asset: asset, retryAttempts: retryAttempts - 1)
}
return img
}
Run Code Online (Sandbox Code Playgroud)
这里的区别在于递归重试。这对我来说 100% 有效。
我发现这与网络或 iCloud 无关。它偶尔会失败,即使在完全本地化的图像上也是如此。有时是我相机的图像,有时是从网络上保存的图像。
我没有找到解决方法,但是受@Nadzeya 启发的一种解决方法对我来说 100% 的时间都有效,就是总是请求目标大小等于资产大小。
例如。
PHCachingImageManager().requestImage(for: asset,
targetSize: CGSize(width: asset.pixelWidth, height: asset.pixelHeight) ,
contentMode: .aspectFit,
options: options,
resultHandler: { (image, info) in
if (image == nil) {
print("Error loading image")
print("\(info)")
} else {
view.image = image
}
});
Run Code Online (Sandbox Code Playgroud)
我相信这样做的缺点是我们将完整图像恢复到内存中,然后强制 ImageView 进行缩放,但至少在我的用例中,没有明显的性能问题,而且是比加载模糊或零图像要好得多。
这里可能的优化是仅当图像返回为 nil 时才以资产大小重新请求图像。
我尝试了很多东西
Optimize Storage在“设置”中的“iCloud 照片”中禁用:不起作用requestImage到后台队列:不起作用PHImageManagerMaximumSize:不工作isNetworkAccessAllowed:不工作PHImageRequestOptions,比如version,deliveryMode,resizeMode:不工作progressHandler:不起作用requestImage再次调用它失败的情况:不工作我得到的只是 nilUIImage和 info with PHImageResultDeliveredImageFormatKey,就像在这个雷达中照片框架不返回特定资产的错误或图像
使用方面适合
什么对我有用,请参阅https://github.com/hyperoslo/Gallery/blob/master/Sources/Images/Image.swift#L34
targetSize与 < 200 一起使用:这就是我可以加载缩略图的原因aspectFit:指定contentMode为我做的伎俩这是代码
let options = PHImageRequestOptions()
options.isSynchronous = true
options.isNetworkAccessAllowed = true
var result: UIImage? = nil
PHImageManager.default().requestImage(
for: asset,
targetSize: size,
contentMode: .aspectFit,
options: options) { (image, _) in
result = image
}
return result
Run Code Online (Sandbox Code Playgroud)
异步获取
以上可能会导致竞争条件,因此请确保异步获取,这意味着没有isSynchronous。看看https://github.com/hyperoslo/Gallery/pull/72
我也看到了这一点,唯一对我有用的就是设置options.isSynchronous = false。我的具体选择是:
options.isNetworkAccessAllowed = true
options.deliveryMode = .highQualityFormat
options.version = .current
options.resizeMode = .exact
options.isSynchronous = false
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
16557 次 |
| 最近记录: |