文档说:
PHImageResultIsInCloudKey:一个布尔值,指示照片资产数据是存储在本地设备上还是必须从iCloud下载。 (NSNumber)如果是,则不提供图像,因为必须从iCloud下载资产数据。要下载数据,请提交另一个请求,并为networkAccessAllowed选项指定是。
但是当资产存储在iCloud照片库中时,即使它已经完全下载到设备(在我的应用程序中下载了它,也在“照片”应用程序中也打开了它),此键始终为。
如果图像不可用,我希望给用户下载的可能性(但不要自动进行,至少在没有Wifi的情况下不要这样做)。
那么,如何确定是否需要下载图像?
更加好奇:当我的结果块requestImageForAsset:targetSize:contentMode:options:resultHandler:
调用了需要下载的图像,在交付了较小且降级的版本后,我得到了一个最后一个请求为requestImage == nil的呼叫。
在这种情况下,降级为否,即使我没有图像,由于至今仍只能从本地使用照片应用程序中的小缩略图,因此仍必须从iCloud下载图像。
我在具有不同iOS 8版本(8.1.x,8.2 beta,8.3 beta)的iPhone和iPad上进行了测试,其行为始终相同。
一旦在“照片”应用中打开图像,结果处理程序的最后一次调用将具有完整大小的图像,但PHImageResultIsInCloudKey仍为“是”。
这是我如何请求图像的一些代码:
PHImageRequestOptions *options = [[PHImageRequestOptions alloc]init];
options.deliveryMode = PHImageRequestOptionsDeliveryModeOpportunistic;
options.networkAccessAllowed = NO;
[self.imageManager requestImageForAsset:asset targetSize:size contentMode:PHImageContentModeAspectFill options:options resultHandler:^(UIImage *requestedImage, NSDictionary *info) {
// Checking for requestedImage and the info keys here
// When a full sized image was loaded, the result of PHImageResultIsInCloudKey is still YES
// When a full sized image couldn't be loaded cause it's in the cloud, isDegraded is NO and PHImageResultIsInCloudKey is YES (as always) and requestedImage is nil
}];
我可以确认PHImageResultIsInCloudKey不可靠。对于存储在iCloud中的图像,即使原始图像已下载到设备,它也会返回1。此行为与文档相反,我建议在radar.apple.com报告一个错误。我认为PhotoKit仍然是一个非常不成熟的框架-它包含许多问题以及一些奇怪的概念性决定。
如果在requestImageDataForAsset:
设置为networkAccessAllowed
的情况下调用NO
,如果尚未从iCloud下载剪辑,则返回的imageData
将为nil
。否则,即使剪辑存储在iCloud中,它也会返回实际数据。
PHImageManager *manager = [PHImageManager defaultManager];
PHImageRequestOptions *options = [[PHImageRequestOptions alloc] init];
options.networkAccessAllowed = NO;
[manager
requestImageDataForAsset:asset
options:options
resultHandler:^(NSData * _Nullable imageData, NSString * _Nullable dataUTI, UIImageOrientation orientation, NSDictionary * _Nullable info) {
if ([[info valueForKey:PHImageResultIsInCloudKey] boolValue]) {
// Image is in iCloud
if (imageData) {
// Image is downloaded
} else {
// Image is not downloaded
}
}
}];
您可以使用progressHandler来检查PHAsset是否来自iCloud。
__block BOOL isPhotoInICloud = NO;
PHImageRequestOptions *options = [[PHImageRequestOptions alloc] init];
options.progressHandler = ^(double progress, NSError *error, BOOL *stop, NSDictionary *info){
isPhotoInICloud = YES;
// some code to update the download progress
});
options.networkAccessAllowed = YES;
options.deliveryMode = PHImageRequestOptionsDeliveryModeHighQualityFormat;
options.synchronous = NO;
[[PHImageManager defaultManager] requestImageForAsset:asset targetSize:PHImageManagerMaximumSize contentMode:PHImageContentModeAspectFit options:options resultHandler:^(UIImage * _Nullable result, NSDictionary * _Nullable info) {
// use the options to get the high quality image for only once time.
});
检查PHAsset是否仍在云中的最佳方法是尝试通过PHImageManager并使用networkAccessAllowed = NO来访问它,如果您未获取图像/资产,那么您知道它仍在云中(并且它不会被下载):
+ (void)checkCloudStatusForPHAsset:(PHAsset*)phAsset completion:(void (^)(BOOL isInCloud))completionBlock
{
if (phAsset) {
if (phAsset.mediaType == PHAssetMediaTypeVideo) {
PHVideoRequestOptions *options = [[PHVideoRequestOptions alloc] init];
options.version = PHVideoRequestOptionsVersionOriginal;
options.deliveryMode = PHVideoRequestOptionsDeliveryModeHighQualityFormat;
options.networkAccessAllowed = NO;
[[PHImageManager defaultManager] requestAVAssetForVideo:phAsset options:options resultHandler:^(AVAsset * _Nullable asset, AVAudioMix * _Nullable audioMix, NSDictionary * _Nullable info) {
completionBlock(asset == nil);
}];
}
else if (phAsset.mediaType == PHAssetMediaTypeImage) {
PHImageRequestOptions *options = [[PHImageRequestOptions alloc] init];
options.version = PHImageRequestOptionsVersionOriginal;
options.deliveryMode = PHImageRequestOptionsDeliveryModeHighQualityFormat;
options.resizeMode = PHImageRequestOptionsResizeModeNone;
options.networkAccessAllowed = NO;
[[PHImageManager defaultManager] requestImageDataForAsset:phAsset options:options resultHandler:^(NSData * _Nullable imageData, NSString * _Nullable dataUTI, UIImageOrientation orientation, NSDictionary * _Nullable info) {
completionBlock(imageData == nil);
}];
}
else {
completionBlock(NO);
}
}
else {
completionBlock(NO);
}
}
以防万一有人在尝试解决iOS 13中的错误时偶然发现此问题。
[此线程中的方法自iOS 8起已被弃用。
在iOS 13中,您需要调用此方法:
- (PHImageRequestID)requestImageDataAndOrientationForAsset:(PHAsset *)asset
options:(PHImageRequestOptions *)options
resultHandler:(void (^)(NSData *imageData, NSString *dataUTI, CGImagePropertyOrientation orientation, NSDictionary *info))resultHandler;