FetchAssetsWithLocalIdentifiers 返回空数组

Posted

技术标签:

【中文标题】FetchAssetsWithLocalIdentifiers 返回空数组【英文标题】:FetchAssetsWithLocalIdentifiers returns empty array 【发布时间】:2016-09-17 16:39:27 【问题描述】:

我正在使用Photos.Framework 将相机拍摄的照片保存到我的图库中并检索它们。

这是我用来存储照片的代码:

    __block PHAssetCollection *album = [self getMyAlbumWithName:@"MyAlbumName"];
    if(album == nil)
    
        [self makeAlbumWithTitle:@"MyAlbumName" onSuccess:^(NSString *AlbumId) 

             album = [self getMyAlbumWithName:@"MyAlbumName"];
            [self addNewAssetWithImage:_imageToStore toAlbum:album onSuccess:^(NSString *ImageId) 
            
                  _imageLocalIdentifier = imageId;
             onError:^(NSError *error) 
                // No need to do anything
            ];
         onError:^(NSError *error) 
            // No need to do anything
        ];
    
    else
    
        [self addNewAssetWithImage:_imageToStore toAlbum:album onSuccess:^(NSString *ImageId) 
        
          _imageLocalIdentifier = imageId;
         onError:^(NSError *error) 
            // No need to do anything
        ];
     

-(PHAssetCollection *)getMyAlbumWithName:(NSString*)AlbumName

    PHFetchResult *assetCollections = [PHAssetCollection fetchAssetCollectionsWithType:PHAssetCollectionTypeAlbum
                                                                               subtype:PHAssetCollectionSubtypeAlbumRegular
                                                                           options:nil];
    NSLog(@"assetCollections.count = %lu", assetCollections.count);
    if (assetCollections.count == 0) return nil;

    __block PHAssetCollection * myAlbum;
    [assetCollections enumerateObjectsUsingBlock:^(PHAssetCollection *album, NSUInteger idx, BOOL *stop) 
    NSLog(@"album:%@", album);
    NSLog(@"album.localizedTitle:%@", album.localizedTitle);
    if ([album.localizedTitle isEqualToString:AlbumName]) 
        myAlbum = album;
        *stop = YES;
        
    ];

    if (!myAlbum) return nil;
    return myAlbum;


-(void)makeAlbumWithTitle:(NSString *)title onSuccess:(void(^)(NSString *AlbumId))onSuccess onError: (void(^)(NSError * error)) onError

    //Check weather the album already exist or not
    if (![self getMyAlbumWithName:title])
    
        [[phphotoLibrary sharedPhotoLibrary] performChanges:^
            // Request editing the album.
            PHAssetCollectionChangeRequest *createAlbumRequest = [PHAssetCollectionChangeRequest creationRequestForAssetCollectionWithTitle:title];
            // Get a placeholder for the new asset and add it to the album editing request.
            PHObjectPlaceholder * placeHolder = [createAlbumRequest placeholderForCreatedAssetCollection];
            if (placeHolder)
            
                onSuccess(placeHolder.localIdentifier);
            
         completionHandler:^(BOOL success, NSError *error) 
            NSLog(@"Finished adding asset. %@", (success ? @"Success" : error));
            if (error)
            
                onError(error);
            
        ];
    


-(void)addNewAssetWithImage:(UIImage *)image
                    toAlbum:(PHAssetCollection *)album
                  onSuccess:(void(^)(NSString *ImageId))onSuccess
                    onError: (void(^)(NSError * error)) onError

     [[PHPhotoLibrary sharedPhotoLibrary] performChanges:^
        // Request creating an asset from the image.
        PHAssetChangeRequest *createAssetRequest = [PHAssetChangeRequest creationRequestForAssetFromImage:image];
        // Request editing the album.
        PHAssetCollectionChangeRequest *albumChangeRequest = [PHAssetCollectionChangeRequest changeRequestForAssetCollection:album];
        // Get a placeholder for the new asset and add it to the album editing request.
        PHObjectPlaceholder * placeHolder = [createAssetRequest placeholderForCreatedAsset];
        [albumChangeRequest addAssets:@[ placeHolder ]];
        NSLog(@"%@",placeHolder.localIdentifier);
        if (placeHolder) 
            onSuccess(placeHolder.localIdentifier);
        
     completionHandler:^(BOOL success, NSError *error) 
        NSLog(@"Finished adding asset. %@", (success ? @"Success" : error));
        if (error) 
            onError(error);
        
    ];

这是我用来检索这张照片的代码:

    PHImageManager *imgManager = [[PHImageManager alloc] init];
    PHFetchResult* fetchResult = [PHAsset fetchAssetsWithLocalIdentifiers:@[_imageLocalIdentifier] options:nil];
    if([fetchResult count] > 0)
    
        PHAsset *asset = [fetchResult objectAtIndex:0];
        PHImageRequestOptions *option = [PHImageRequestOptions new];
        option.synchronous = NO;
        option.version = PHImageRequestOptionsVersionCurrent;
        option.networkAccessAllowed = YES;
        option.deliveryMode = PHImageRequestOptionsDeliveryModeOpportunistic;
        option.resizeMode = PHImageRequestOptionsResizeModeFast;
        [imgManager requestImageForAsset:asset
                              targetSize:CGSizeMake(CAMERA_GALLERY_SIZE, CAMERA_GALLERY_SIZE)
                             contentMode:PHImageContentModeDefault
                                 options:option
                           resultHandler:^(UIImage *result, NSDictionary *info) 
                               [cell.photoIV setImage:result];
                           ];
    

使用这段代码,存储了 12 张照片的样本(它们在我的相册中没问题),其中 4 或 5 个本地标识符返回一个空的提取结果。 这在 ios 8、iOS 9 和 iOS 10 中进行了测试(使用 iOS 10 确实更糟,因为几乎所有的 fetch 结果都是空的)。

我读过类似的东西是以前版本的 iOS 中的一个错误,但我想现在不是这个原因。

我试过用这种方法来检索照片:

- (PHAsset *)getAssetFromGallery:(NSString *)identifier

    PHAsset *asset = [PHAsset fetchAssetsWithLocalIdentifiers:@[identifier] options:nil].lastObject;
    if(asset != nil)
        return asset;

    __block PHAsset *result;
    PHFetchResult *userAlbums = [PHAssetCollection fetchAssetCollectionsWithType:PHAssetCollectionTypeAlbum subtype:PHAssetCollectionSubtypeAny options:nil];

    PHFetchOptions *fetchOptions = [[PHFetchOptions alloc] init];
    [fetchOptions setPredicate:[NSPredicate predicateWithFormat:@"localIdentifier == %@", identifier]];

    [userAlbums enumerateObjectsUsingBlock:^(id  _Nonnull objectCollection, NSUInteger idx, BOOL * _Nonnull stopCollectionEnumeration) 

        PHAssetCollection *collection = nil;
        if(![objectCollection isKindOfClass:[PHAssetCollection class]])
            return;
        collection = (PHAssetCollection *)objectCollection;

        PHFetchResult *assetsFetchResult = [PHAsset fetchAssetsInAssetCollection:collection options:fetchOptions];
        [assetsFetchResult enumerateObjectsUsingBlock:^(id  _Nonnull objectAsset, NSUInteger idx, BOOL * _Nonnull stopAssetEnumeration) 
            PHAsset *asset = nil;
            if(![objectAsset isKindOfClass:[PHAsset class]])
                return;
            result = asset;
            *stopAssetEnumeration = YES;
            *stopCollectionEnumeration = YES;
        ];

    ];

    return asset;

我尝试使用PHAssetCollectionSubtypeAlbumMyPhotoStream 而不是PHAssetCollectionSubtypeAny。 我试过用@"localIdentifier ==[cd] %@"而不是@"localIdentifier == %@". 并且总是相同的结果,很多时候获取结果是空的。 知道发生了什么吗?

【问题讨论】:

你找到原因了吗?同样的事情发生在我身上 是的,原因是我在调用 onSuccess(placeHolder.localIdentifier);在 performChanges 块内而不是在 completionHandler 块内。我将用我的代码更新来回答我自己的问题,以便您检查。 感谢您的回答,我会检查您的回答:) 【参考方案1】:

我的问题是我没有以正确的方式保存照片,我正在调用 onSuccess(placeHolder.localIdentifier);在 performChanges 块内而不是在 completionHandler 块内。

这是我现在用来保存照片的代码:

__block PHAssetCollection *album = [AuxiliaryFunctions getMyAlbumWithName:@"MyAlbumName" orWithIdentifier:@""];
if(album == nil)
    [self makeAlbumWithTitle:@"MyAlbumName" onSuccess:^(NSString *AlbumId) 

        album = [self getMyAlbumWithName:@"MyAlbumName" orWithIdentifier:AlbumId];
        [self addNewAssetWithImage:_imageToStore toAlbum:album onSuccess:^(NSString *ImageId) 
         
            _imageLocalIdentifier = imageId;
         onError:^(NSError *error) 
            // No need to do anything
        ];
     onError:^(NSError *error) 
        // No need to do anything
    ];
else

    [self addNewAssetWithImage:_imageToStore toAlbum:album onSuccess:^(NSString *ImageId) 
     
            _imageLocalIdentifier = imageId;
     onError:^(NSError *error) 
        // No need to do anything
    ];



-(PHAssetCollection *)getMyAlbumWithName:(NSString*)AlbumName orWithIdentifier:(NSString *)identifier

    PHFetchResult *assetCollections = nil;
    if(![identifier isEqualToString:@""])
    
        PHFetchOptions *options = [PHFetchOptions new];
        options.predicate = [NSPredicate predicateWithFormat:@"localIdentifier = %@ OR title = %@", identifier, AlbumName];
        assetCollections = [PHAssetCollection fetchAssetCollectionsWithLocalIdentifiers:@[identifier]
                                                                                options:options];
    
    else
    
        PHFetchOptions *options = [PHFetchOptions new];
        options.predicate = [NSPredicate predicateWithFormat:@"title = %@", AlbumName];
        assetCollections = [PHAssetCollection fetchAssetCollectionsWithType:PHAssetCollectionTypeAlbum
                                                                                   subtype:PHAssetCollectionSubtypeAny
                                                                                   options:options];
    

    NSLog(@"assetCollections.count = %lu", assetCollections.count);
    if (assetCollections.count == 0) return nil;

    __block PHAssetCollection * myAlbum;
    [assetCollections enumerateObjectsUsingBlock:^(PHAssetCollection *album, NSUInteger idx, BOOL *stop) 
        NSLog(@"album:%@", album);
        NSLog(@"album.localizedTitle:%@", album.localizedTitle);
        if ([album.localizedTitle isEqualToString:AlbumName]) 
            myAlbum = album;
            *stop = YES;
        
    ];

    if (!myAlbum) return nil;
    return myAlbum;


-(void)makeAlbumWithTitle:(NSString *)title onSuccess:(void(^)(NSString *AlbumId))onSuccess onError: (void(^)(NSError * error)) onError

    __block NSString *localIdentifier = @"";
    //Check weather the album already exist or not
    if (![self getMyAlbumWithName:title orWithIdentifier:@""])
    
        [[PHPhotoLibrary sharedPhotoLibrary] performChanges:^
            // Request editing the album.
            PHAssetCollectionChangeRequest *createAlbumRequest = [PHAssetCollectionChangeRequest creationRequestForAssetCollectionWithTitle:title];
            // Get a placeholder for the new asset and add it to the album editing request.
            PHObjectPlaceholder * placeHolder = [createAlbumRequest placeholderForCreatedAssetCollection];
            if (placeHolder)
            
                localIdentifier = placeHolder.localIdentifier;
                // This line was the problem
                //onSuccess(localIdentifier);
            
         completionHandler:^(BOOL success, NSError *error) 
            NSLog(@"Finished adding asset. %@", (success ? @"Success" : error));
            if(success)
            
                onSuccess(localIdentifier);
            
            if (error)
            
                onError(error);
            
        ];
    


-(void)addNewAssetWithImage:(UIImage *)image
                    toAlbum:(PHAssetCollection *)album
                  onSuccess:(void(^)(NSString *ImageId))onSuccess
                    onError: (void(^)(NSError * error)) onError

    __block NSString *localIdentifier = @"";
    [[PHPhotoLibrary sharedPhotoLibrary] performChanges:^
        // Request creating an asset from the image.
        PHAssetChangeRequest *createAssetRequest = [PHAssetChangeRequest creationRequestForAssetFromImage:image];
        // Request editing the album.
        PHAssetCollectionChangeRequest *albumChangeRequest = [PHAssetCollectionChangeRequest changeRequestForAssetCollection:album];
        // Get a placeholder for the new asset and add it to the album editing request.
        PHObjectPlaceholder * placeHolder = [createAssetRequest placeholderForCreatedAsset];
        [albumChangeRequest addAssets:@[ placeHolder ]];
        NSLog(@"%@",placeHolder.localIdentifier);
        if (placeHolder) 
            localIdentifier = placeHolder.localIdentifier;
            // This line was the problem
            //onSuccess(localIdentifier);
        
     completionHandler:^(BOOL success, NSError *error) 
        NSLog(@"Finished adding asset. %@", (success ? @"Success" : error));
        if(success)
        
            onSuccess(localIdentifier);
        
        if (error)
        
            onError(error);
        
    ];

【讨论】:

既然标识符作为第一个参数传递给 fetchAssetCollectionsWithLocalIdentifiers,为什么我们需要为 localIdentifier 指定谓词?这似乎是多余的。

以上是关于FetchAssetsWithLocalIdentifiers 返回空数组的主要内容,如果未能解决你的问题,请参考以下文章