照片框架requestImageDataForAsset偶尔会失败

时间:2015-01-27 12:22:29

标签: ios objective-c photosframework

我使用iOS8.1上的照片框架并使用requestImageDataForAsset请求资产的图像数据...大部分时间它都可以工作,我得到的图像数据和包含您在下面看到的内容的字典。但有时调用完成,但数据为零,字典包含三个通用的查找条目。

调用按顺序执行并在同一个线程上执行。它不是特定于任何特定图像。错误将发生在我过去成功打开的图像上。有没有人遇到过这个?

+ (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;
})

这是偶尔得到的。图像数据为零。字典包含的不多。

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

4 个答案:

答案 0 :(得分:5)

我遇到了类似症状的问题,其中requestImageDataForAsset返回了无图像数据,但也出现了如下控制台错误消息:

[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试图使用/var/mobile/Media/PhotoData/PhotoCloudSharingData/中的文件本地缓存(来自信息词典&#39; s PHImageFileURLKey键)并且缓存可能已损坏我想到了如何清除缓存。

切换&#39; iCloud照片共享&#39;切换到iOS&#39; 设置 - &gt;账户&amp;密码 - &gt; iCloud - &gt;照片似乎已经成功了。 requestImageDataForAsset现在正在为之前失败的资产工作。

2018年3月9日更新

我现在可以重现这个问题。它似乎是在从iTunes恢复备份后发生的:

  1. 使用iOS应用程序并从iCloud共享相册中检索照片。
  2. 使用iTunes备份iOS设备。
  3. 使用iTunes恢复备份。
  4. 再次使用该应用程序从iCloud共享相册中检索相同的照片现在失败并显示上述控制台消息。
  5. 切换&#39; iCloud照片共享&#39;开关修复它仍然。据推测,恢复过程会以某种方式破坏某些缓存。我已将其报告为Apple的Bug 38290463。

答案 1 :(得分: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];
    }];
}

答案 2 :(得分: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的媒体网址导致资产为零而requestImageDataForAsset返回默认信息对象时出现问题。

答案 3 :(得分:0)

以下代码可能会有所帮助。我认为PHImageRequestOptions类存在错误,因此我通过了nil,然后修复了该错误。

 private static String clientId = "FILL-IN-HERE";
 private static String authTokenEndpoint = "FILL-IN-HERE";
 private static String clientKey = "FILL-IN-HERE";

 AccessTokenProvider provider = new ClientCredsTokenProvider(authTokenEndpoint, clientId, clientKey); 
private static String accountFQDN = "FILL-IN-HERE";  // full account FQDN, not just the account name
ADLStoreClient client = ADLStoreClient.createClient(accountFQDN, provider);

try {
String filename = "/a/b/c.txt";
OutputStream stream = client.createFile(filename, IfExists.OVERWRITE  );
PrintStream out = new PrintStream(stream);
for (int i = 1; i <= 10; i++) {
    out.println("This is line #" + i);
    out.format("This is the same line (%d), but using formatted output. %n", i);
}
out.close();
System.out.println("File created.");

}catch(Exception ex){
 System.out.format(" Exception: %s%n Message: %s%n", ex.getClass().getName(), ex.getMessage());
}