照片框架 requestImageDataForAsset 偶尔会失败

Photos Framework requestImageDataForAsset occasionally fails

我在 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;
})

你可能是在遍历一个数组,内存没有及时释放,你可以试试下面的代码。确保 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];
    }];
}

时隔很久再回到这里,我已经解决了很大一部分问题。没有神秘,只有糟糕的代码:

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 出现问题,导致资产为 nil 并且 requestImageDataForAsset return 成为默认信息对象。

我遇到了类似症状的问题,其中 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,然后升级到 11.2 后,问题突然开始出现在特定设备上,只有 iCloud 共享相册中的资产。 5.考虑到 requestImageDataForAsset 可能正在尝试使用本地缓存在 /var/mobile/Media/PhotoData/PhotoCloudSharingData/ 中的文件(来自信息字典的 PHImageFileURLKey 键)并且缓存可能已损坏,我考虑了如何清除该缓存。

切换 iOS 中的 'iCloud Photo Sharing' 开关 设置 -> 帐户和密码 -> iCloud -> 照片 似乎已经成功了。 requestImageDataForAsset 现在正在为那些以前失败的资产工作。

2018 年 3 月 9 日更新

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

  1. 使用 iOS 应用程序并从 iCloud 共享相册中检索照片。
  2. 使用 iTunes 备份 iOS 设备。
  3. 使用 iTunes 恢复备份。
  4. 再次使用该应用从 iCloud 共享相册检索相同的照片现在失败并显示上述控制台消息。

切换 'iCloud Photo Sharing' 开关仍然可以修复它。据推测,恢复过程以某种方式破坏了一些缓存。我已将其作为错误 38290463 报告给 Apple。

以下代码可能会有所帮助。我认为 class PHImageRequestOptions 有一个错误,所以我通过 nil ,然后修复错误。

   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);