Wonton
Wonton

Reputation: 1143

FetchAssetsWithLocalIdentifiers returns empty array

I'm using Photos.Framework to save photos taken from the camera into my gallery and to retrieve them.

This is the code I'm using to store the photos:

    __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);
        }
    }];
}

And this is the code I'm using to retrieve this photo:

    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];
                           }];
    }

With this piece of code, over a sample of 12 photos stored (they are ok in my album) 4 or 5 of their localidentifiers returns an empty fetch results. This is tested in iOS 8, iOS 9 and iOS 10 (with iOS 10 it's indeed worse because almost all of the fetch results are empty).

I've read that something similar to this was a bug in previous versions of iOS, but I guess this is not the reason now.

I've tried with this method to retrieve the photos:

- (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;
}

I've tried with PHAssetCollectionSubtypeAlbumMyPhotoStream instead of PHAssetCollectionSubtypeAny. And I've tried with @"localIdentifier ==[cd] %@" instead of @"localIdentifier == %@". And always the same results, lots of times the fetch results is empty. Any idea of what is it happening?

Upvotes: 4

Views: 2797

Answers (1)

Wonton
Wonton

Reputation: 1143

My problem was that I wasn't saving the photos in the right way, I was calling onSuccess(placeHolder.localIdentifier); inside the performChanges block instead of inside the completionHandler block.

This is the code I'm using now to save the photos:

__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);
        }
    }];
}

Upvotes: 3

Related Questions