Photos框架请求Asset的ImageData时偶尔会失败。

21
我正在使用iOS 8.1上的照片框架,并使用requestImageDataForAsset请求资产的图像数据... 大多数情况下,它可以正常工作并且我能够获得图像数据和包含如下所示内容的字典。但有时调用会完成,但数据为nil,而字典包含三个通用的条目。
这些调用是按顺序执行且在同一个线程上执行的。它无关任何特定的图像。错误会发生在我过去成功打开的图像上。有人遇到过这种情况吗?
+ (NSData *)retrieveAssetDataPhotosFramework:(NSURL *)urlMedia resolution:(CGFloat)resolution imageOrientation:(ALAssetOrientation*)imageOrientation {

    __block NSData *iData = nil;

    PHFetchResult *result = [PHAsset fetchAssetsWithALAssetURLs:@[urlMedia] options:nil];
    PHAsset *asset = [result firstObject];

    PHImageManager *imageManager = [PHImageManager defaultManager];
    PHImageRequestOptions *options = [[PHImageRequestOptions alloc]init];
    options.synchronous = YES;
    options.version = PHImageRequestOptionsVersionCurrent;

    @autoreleasepool {
        [imageManager requestImageDataForAsset:asset options:options resultHandler:^(NSData *imageData, NSString *dataUTI, UIImageOrientation orientation, NSDictionary *info) {
            iData = [imageData copy];
            NSLog(@"requestImageDataForAsset returned info(%@)", info);
            *imageOrientation = (ALAssetOrientation)orientation;
        }];
    }

    assert(iData.length != 0);
    return iData;
}

这是我想得到的结果,其中包括图像数据和元数据字典:
requestImageDataForAsset returned info({
    PHImageFileDataKey = <PLXPCShMemData: 0x1702214a0> bufferLength=1753088 dataLength=1749524;
    PHImageFileOrientationKey = 1;
    PHImageFileSandboxExtensionTokenKey = "6e14948c4d0019fbb4d14cc5e021199f724f0323;00000000;00000000;000000000000001a;com.apple.app-sandbox.read;00000001;01000003;000000000009da80;/private/var/mobile/Media/DCIM/107APPLE/IMG_7258.JPG";
    PHImageFileURLKey = "file:///var/mobile/Media/DCIM/107APPLE/IMG_7258.JPG";
    PHImageFileUTIKey = "public.jpeg";
    PHImageResultDeliveredImageFormatKey = 9999;
    PHImageResultIsDegradedKey = 0;
    PHImageResultIsInCloudKey = 0;
    PHImageResultIsPlaceholderKey = 0;
    PHImageResultWantedImageFormatKey = 9999;
})

以下是我偶尔看到的情况。图像数据为 nil。字典内容不多。

requestImageDataForAsset returned info({
    PHImageResultDeliveredImageFormatKey = 9999;
    PHImageResultIsDegradedKey = 0;
    PHImageResultWantedImageFormatKey = 9999;
})

我也遇到了这个问题,对于共享的iCloud流中的图像也是如此。目前还没有解决方案。 - an0
当尝试使用options.synchronous = YES从iCloud共享照片流(又名Shared Album)中获取尚未下载的资源的图像时,似乎会经常发生(接近100%)。如果图像已经被Photos应用程序或我的应用程序异步地下载并缓存,则可以正常工作。否则,同步下载总是失败的。我已经尝试过iOS 8.x、9.0和9.1,结果相同。 - LenK
我也遇到了这个问题。我的解决方法是将 options.synchronous 设置为 NO。 - Jerry YY Rain
4个回答

5
我遇到了一个类似的问题,其中requestImageDataForAsset返回了nil图像数据,但是还伴随着控制台错误消息,如下所示: [Generic] Failed to load image data for asset <PHAsset: 0x13d041940> 87CCAFDC-A0E3-4AC9-AD1C-3F57B897A52E/L0/001 mediaType=1/0, sourceType=2, (113x124), creationDate=2015-06-29 04:56:34 +0000, location=0, hidden=0, favorite=0 with format 9999
在我的情况下,在将iOS 10.x升级到11.0.3之后,问题突然只发生在特定设备上,仅对iCloud共享相册中的资源造成影响,并一直持续到11.2.5。我想到可能是requestImageDataForAsset试图使用从信息字典的PHImageFileURLKey键缓存的本地文件(位于/var/mobile/Media/PhotoData/PhotoCloudSharingData/),并且缓存可能已经损坏,因此考虑了如何清除该缓存。
在iOS的“设置->账户和密码->iCloud->照片”中切换“iCloud照片共享”开关似乎解决了问题。现在,requestImageDataForAsset正在为之前失败的资源工作。
更新于2018年3月9日:
我现在可以重现此问题。似乎在从iTunes恢复备份后出现以下情况:
1.使用iOS应用程序并从iCloud共享的相册中检索照片。 2.使用iTunes备份iOS设备。 3.使用iTunes还原备份。 4.再次使用应用程序从iCloud共享的相册检索相同的照片,现在会失败,并显示上面的控制台消息。
切换“iCloud照片共享”开关仍然可以解决该问题。假设恢复过程以某种方式损坏了一些缓存。我已向Apple报告了Bug 38290463。

但是你如何告诉用户这样做呢?如果应用程序本身有解决方案,那将是很棒的。 - d4Rk
1
@d4Rk 这是一个很好的观点。让应用程序自己准确地检测到这种情况,然后可能将用户引导到支持页面,描述如何尝试纠正问题,这将是理想的。但要准确地检测出问题可能会很棘手,因为你在应用程序中真正拥有的只是一个空结果,没有其他信息来区分其他可能的故障原因。 - user2067021
2
@AhmadF 这是链接:https://bugreport.apple.com/web/?problemID=38290463 但我不认为苹果的系统允许外部人员查看彼此的漏洞报告,所以我不确定它是否有用。 - user2067021
1
抱歉,出了些问题。 这个错误不存在或者您没有访问权限。不管怎样还是谢谢您的支持 ;) - Ahmad F
1
这不是一个 bug。它与 设置 -> 密码和帐户 -> iCloud -> 照片 中的 优化 iPhone 储存空间 选项相关。更改为 下载并保留原件 或通过将 PHImageRequestOptions.isNetworkAccessAllowed = true 传递到 requestImageData(for asset: options: resultHandler:) - Kirow
显示剩余2条评论

2

您可能正在遍历一个数组,并且内存没有及时释放,您可以尝试以下代码。确保theData被标记为__block

@autoreleasepool {
    [imageManager requestImageDataForAsset:asset options:options resultHandler:^(NSData *imageData, NSString *dataUTI, UIImageOrientation orientation, NSDictionary *info) {
        NSLog(@"requestImageDataForAsset returned info(%@)", info);
        theData = [imageData copy];
    }];
}

谢谢gabbler。@自动释放池确实有助于在负载下减少内存使用(连续检索多个图像),但问题仍然存在。 - Dan Loughney
发布你的代码以连续检索多张图片。 - gabbler
我已更新帖子以显示整个方法。我已经将requestImageDataForAsset封装在一个类方法中,以使调用者不必关心iOS的版本。对于在iOS7上调用的ALAssetsLibrary也有类似的方法。代码不是在循环中调用的,而是可能会发生多个事件,在同一时间请求不同的图像。问题是不一致的。在过去的一天中根本没有发生过。有时它会偶尔发生。有时在请求照片时50%的时间会发生。 - Dan Loughney
1
对我有用。我的确在循环中,大约在第800张图像时就不会返回任何数据了。这应该被标记为正确的。 - dloomb
8
这不是一个修复方法:我可以在我的个人(iCloud相册)库中使用相同的4个资源并一直重现这个问题。问题似乎是Photos框架中的真正错误或者是库中这些特定资源的某些问题。现在的问题是,有什么有效的解决方法。 - Jonathan Crooke

0

好久不见,回到这个问题上,我解决了我的问题的一大部分。没有什么神秘的,只是写得不好的代码:

PHFetchResult *result = [PHAsset fetchAssetsWithALAssetURLs:@[urlMedia] options:nil];
PHAsset *asset = [result firstObject];

if (asset != nil) { // the fix
    PHImageManager *imageManager = [PHImageManager defaultManager];
    PHImageRequestOptions *options = [[PHImageRequestOptions alloc]init];
    ...
}

我遇到的最常见问题是传递给fetchAssetsWithALAssetURLs的媒体URL有问题,导致资源为空,并且requestImageDataForAsset返回默认信息对象。

你解决了“不”获取空资产的问题吗? - WYS

0
以下代码可能会有所帮助。我认为 PHImageRequestOptions 类存在一个 bug,因此我传入了 nil,并修复了该 bug。
   dispatch_semaphore_t sema = dispatch_semaphore_create(0);
            [[PHImageManager defaultManager] requestImageDataForAsset:asset options:nil resultHandler:^(NSData * _Nullable imageData, NSString * _Nullable dataUTI, UIImageOrientation orientation, NSDictionary * _Nullable info) {
                assetModel.size = imageData.length;
                NSString *filename = [asset valueForKey:@"filename"];
                assetModel.fileName = filename;
                dispatch_semaphore_signal(sema);
            }];
            dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接