web-dev-qa-db-ja.com

与えられたPHAssetがiCloudアセットであることを確認しますか?

PhAssetオブジェクトを取得しようとしています。 iCloudアセットを分離したい。これが私のコードです、

PHFetchResult *cloudAlbums = [PHAssetCollection fetchAssetCollectionsWithType:PHAssetCollectionTypeAlbum subtype:PHAssetCollectionSubtypeAny options:nil];

[cloudAlbums enumerateObjectsUsingBlock:^(PHAssetCollection *collection, NSUInteger idx, BOOL *stop){
    if(collection != nil){

        PHFetchResult *result = [PHAsset fetchAssetsInAssetCollection:collection options:fetchOptions];
        [result enumerateObjectsUsingBlock:^(PHAsset *asset, NSUInteger idx, BOOL *stop)
         {
            // check asset is iCloud asset 

         }];
    }

}];

PHAssetがiCloudアセットであるかどうかを確認する方法を教えてください。

14
rishu1992

これはちょっとしたハックで、必要な情報を見つけるためにリソース配列を掘り下げてデバッグする必要がありました。しかし、それは機能します。これは文書化されていないコードであり、Appleがこのためにアプリを拒否するかどうかはわかりませんが、試してみて、何が起こるかを確認してください。

// asset is a PHAsset object for which you want to get the information    
NSArray *resourceArray = [PHAssetResource assetResourcesForAsset:asset];
BOOL bIsLocallayAvailable = [[resourceArray.firstObject valueForKey:@"locallyAvailable"] boolValue]; // If this returns NO, then the asset is in iCloud and not saved locally yet

また、元のファイル名、ファイルサイズ、ファイルURLなど、アセットリソースから他の有用な情報を取得することもできます。

15
Erfan

実際には2種類の状況があります:1。写真はこのデバイスによってキャプチャされ、iCloudにアップロードされます。次に、progressHandlerを使用して、iCloudのダウンロードが必要かどうかを確認できます。

__block BOOL isPhotoInICloud = NO;
PHImageRequestOptions *options = [[PHImageRequestOptions alloc] init];
options.networkAccessAllowed = YES;
options.deliveryMode = PHImageRequestOptionsDeliveryModeHighQualityFormat;
options.progressHandler = ^(double progress, NSError *error, BOOL *stop, NSDictionary *info){

        isPhotoInICloud = YES;

});

[[PHImageManager defaultManager] requestImageForAsset:asset targetSize:PHImageManagerMaximumSize contentMode:PHImageContentModeAspectFit options:options resultHandler:^(UIImage * _Nullable result, NSDictionary * _Nullable info) {

        if (isPhotoInICloud) {
            // Photo is in iCloud.
        }
});
  1. 写真はiCloudにありますが、他のデバイスからアップロードされています。そして、あなたはそれをあなたの地元の写真ライブラリに保存しませんでした。したがって、progressHandlerブロックが呼び出されることはありません。理由はわかりませんが、本当です。PhotoKitフレームワークのバグのようなものだと思います。この状況で、PHImageResultIsInCloudKeyを使用する場合、それも困難です。 PHImageResultIsInCloudKey値は、requestImageForAssetのresultHandlerブロックでしか知ることができないためです。しかし、それは写真のリクエストが開始された後の時間です。

したがって、少なくとも私の意見では、写真がiCloudに保存されているかどうかを確認する方法はありません。たぶん他のより良い方法があります、私に知らせてください。どうもありがとう!

10
Chris Forever

画像をリクエストすると、アセットがiCloudに存在するかどうかを示す情報辞書のキーを取得します。

[cloudAlbums enumerateObjectsUsingBlock:^(PHAssetCollection *collection, NSUInteger idx, BOOL *stop)
{
    PHFetchResult *result = [PHAsset fetchAssetsInAssetCollection:collection options:fetchOptions];
    [result enumerateObjectsUsingBlock:^(PHAsset *asset, NSUInteger idx, BOOL *stop)
    {  
        PHImageRequestOptions *options = [[PHImageRequestOptions alloc] init];
        options.resizeMode = PHImageRequestOptionsResizeModeFast;
        options.synchronous = YES;
        __block BOOL isICloudAsset = NO;
        [[PHImageManager defaultManager] requestImageForAsset:asset targetSize:imageSize contentMode:PHImageContentModeAspectFit options:options resultHandler:^(UIImage *result, NSDictionary *info) 
        {
            if ([info objectForKey: PHImageResultIsInCloudKey].boolValue) 
            {
                isICloudAsset = YES;
            }
        }]; 
    }];
}];
2
jarora

これがSwift 3バージョンです

func checkVideoType(){
    if selectedAsset != nil {
        guard (selectedAsset.mediaType == .video) else {
            print("Not a valid video media type")
            return
        }
        requestID = checkIsiCloud(assetVideo:selectedAsset, cachingImageManager: catchManager)
    }
}

 func checkIsiCloud(assetVideo:PHAsset,cachingImageManager:PHCachingImageManager) -> PHImageRequestID{

        let opt=PHVideoRequestOptions()
        opt.deliveryMode = .mediumQualityFormat
        opt.isNetworkAccessAllowed=true //iCloud video can play
        return cachingImageManager.requestAVAsset(forVideo:assetVideo, options: opt) { (asset, audioMix, info) in

            DispatchQueue.main.async {
                if (info!["PHImageFileSandboxExtensionTokenKey"] != nil) {
                    self.iCloudStatus=false
                    self.playVideo(videoAsset:asset!)
                }else if((info![PHImageResultIsInCloudKey]) != nil) {
                    self.iCloudStatus=true

                }else{
                   self.iCloudStatus=false
                   self.playVideo(videoAsset:asset!)
                }
            }
    }

}
0

このコードは機能するはずです。このコードを頻繁に呼び出す場合は、PHImageRequestIDによる不要なリクエストをキャンセルしてください。

- (PHImageRequestID)checkIsCloud:(PHAsset *)asset cachingImageManager:(PHCachingImageManager *)cachingImageManager {
    if (asset.mediaType == PHAssetMediaTypeVideo) {
        PHVideoRequestOptions *options = [PHVideoRequestOptions new];
        options.deliveryMode = PHVideoRequestOptionsDeliveryModeMediumQualityFormat;
        return [cachingImageManager requestAVAssetForVideo:asset options:options resultHandler:^(AVAsset * _Nullable avAsset, AVAudioMix * _Nullable audioMix, NSDictionary * _Nullable info) {
            if (asset != self.asset) return;
            dispatch_async(dispatch_get_main_queue(), ^{
                if (info[@"PHImageFileSandboxExtensionTokenKey"]) {
                    self.iCloudStatus = KICloudStatusNone;
                } else if ([info[PHImageResultIsInCloudKey] boolValue]) {
                    self.iCloudStatus = KICloudStatusNormal;
                } else {
                    self.iCloudStatus = KICloudStatusNone;
                }
            });
        }];
    } else {
        return [cachingImageManager requestImageDataForAsset:asset options:nil resultHandler:^(NSData * _Nullable imageData, NSString * _Nullable dataUTI, UIImageOrientation orientation, NSDictionary * _Nullable info) {
            if (asset != self.asset) return;
            dispatch_async(dispatch_get_main_queue(), ^{
                if ([info[PHImageResultIsInCloudKey] boolValue]) {
                    self.iCloudStatus = KICloudStatusNormal;
                } else {
                    self.iCloudStatus = KICloudStatusNone;
                }
            });
        }];
    }
}
0
jft0m

以下は、PhotosアプリのVideosフォルダーにあるすべてのビデオを取得するために実装できるメソッドです。PHFetchRequestの述語を使用して、iCloudではなくiPhone自体に保存されているビデオのみをフィルター処理します。

// Collect all videos in the Videos folder of the Photos app
- (PHFetchResult *)assetsFetchResults {
    __block PHFetchResult *i = self->_assetsFetchResults;
    if (!i) {
        static dispatch_once_t onceToken;
        dispatch_once(&onceToken, ^{
            PHFetchOptions *fetchOptions = [PHFetchOptions new];
            fetchOptions.predicate = [NSPredicate predicateWithFormat:@"(sourceType & %d) != 0", PHAssetSourceTypeUserLibrary];
            PHFetchResult *smartAlbums = [PHAssetCollection fetchAssetCollectionsWithType:PHAssetCollectionTypeSmartAlbum subtype:PHAssetCollectionSubtypeSmartAlbumVideos options:fetchOptions];
            PHAssetCollection *collection = smartAlbums.firstObject;
            if (![collection isKindOfClass:[PHAssetCollection class]]) collection = nil;
            PHFetchOptions *allPhotosOptions = [[PHFetchOptions alloc] init];
            allPhotosOptions.sortDescriptors = @[[NSSortDescriptor sortDescriptorWithKey:@"creationDate" ascending:NO]];
            i = [PHAsset fetchAssetsInAssetCollection:collection options:allPhotosOptions];
            self->_assetsFetchResults = i;
        });
    }

    return i;
}

PHFetchResultに関するAppleのドキュメントには、述語で使用できるのは属性のサブセットのみであると記載されています。したがって、上記のコードが機能しない場合は、PHFetchOptions述語を削除し、PHFetchRequestの対応する参照をnilに置き換えます。

// Collect all videos in the Videos folder of the Photos app
- (PHFetchResult *)assetsFetchResults {
    __block PHFetchResult *i = self->_assetsFetchResults;
    if (!i) {
        static dispatch_once_t onceToken;
        dispatch_once(&onceToken, ^{
            PHFetchResult *smartAlbums = [PHAssetCollection fetchAssetCollectionsWithType:PHAssetCollectionTypeSmartAlbum subtype:PHAssetCollectionSubtypeSmartAlbumVideos options:nil];
            PHAssetCollection *collection = smartAlbums.firstObject;
            if (![collection isKindOfClass:[PHAssetCollection class]]) collection = nil;
            PHFetchOptions *allPhotosOptions = [[PHFetchOptions alloc] init];
            allPhotosOptions.sortDescriptors = @[[NSSortDescriptor sortDescriptorWithKey:@"creationDate" ascending:NO]];
            i = [PHAsset fetchAssetsInAssetCollection:collection options:allPhotosOptions];
            self->_assetsFetchResults = i;
        });
    }

    return i;
}

次に、次の行を追加します。

// Filter videos that are stored in iCloud
- (NSArray *)phAssets {
    NSMutableArray *assets = [NSMutableArray arrayWithCapacity:self.assetsFetchResults.count];
    [[self assetsFetchResults] enumerateObjectsUsingBlock:^(PHAsset *asset, NSUInteger idx, BOOL *stop) {
        if (asset.sourceType == PHAssetSourceTypeUserLibrary)
                 [assets addObject:asset];
     }];

    return [NSArray arrayWithArray:(NSArray *)assets];
}
0
James Bush