ドキュメントによると:
PHImageResultIsInCloudKey:写真アセットデータがローカルデバイスに保存されているか、iCloudからダウンロードする必要があるかを示すブール値。 (NSNumber)YESの場合、アセットデータはiCloudからダウンロードする必要があるため、画像は提供されませんでした。データをダウンロードするには、別のリクエストを送信し、networkAccessAllowedオプションにYESを指定します。
ただし、アセットがiCloudフォトライブラリに保存されている場合、デバイスに完全にダウンロードされている場合でも、このキーは常にYESです(アプリでダウンロードし、フォトアプリで開いた場合でも)。
画像が利用できない場合は、ユーザーにダウンロードできるようにしたいです(ただし、少なくともWifiがない場合は、自動的にダウンロードしないでください)。
では、画像をダウンロードする必要があるかどうかを確認するにはどうすればよいですか?
さらに興味深いことに、ダウンロードする必要のある画像に対してrequestImageForAsset:targetSize:contentMode:options:resultHandler:
の結果ブロックが呼び出されると、小さくて劣化したバージョンが配信された後、requestedImage == nilで最後の呼び出しが行われます。
この場合、劣化はNOです。画像がなく、写真アプリの小さなサムネイルしかローカルで利用できないため、画像をiCloudからダウンロードする必要があります。
私はこれを異なるiOS8バージョン(8.1.x、8.2ベータ、8.3ベータ)のiPhoneとiPadでテストしましたが、動作は常に同じです。
写真アプリで画像を開くと、結果ハンドラーの最後の呼び出しでフルサイズの画像が表示されますが、PHImageResultIsInCloudKeyは引き続きYESになります。
画像をリクエストする方法のコードは次のとおりです。
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はまだ非常に未成熟なフレームワークであり、多くの問題といくつかの奇妙な概念上の決定が含まれています。
networkAccessAllowed
をNO
に設定してrequestImageDataForAsset:
を呼び出すと、クリップが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
}
}
}];
PHAssetがまだクラウドにあるかどうかを確認する最良の方法は、networkAccessAllowed = NOを指定してPHImageManagerを介してアクセスすることです。画像/アセットを取得できない場合は、PHAssetがまだクラウドにあることがわかります(そして勝ちました)ダウンロードされません):
+ (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);
}
}
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.
});
IOS 13のバグを解決しようとしているときに、誰かがこれに遭遇した場合に備えて。
このスレッドのメソッドは、iOS8以降非推奨になっています。
IOS 13では、代わりにこのメソッドを呼び出す必要があります。
- (PHImageRequestID)requestImageDataAndOrientationForAsset:(PHAsset *)asset
options:(PHImageRequestOptions *)options
resultHandler:(void (^)(NSData *imageData, NSString *dataUTI, CGImagePropertyOrientation orientation, NSDictionary *info))resultHandler;