How to compare PHAsset to UIImage

余生长醉 提交于 2019-12-06 00:37:37

You should not compare images, you should instead compare PHAssets or their only useful part named localIdentifier.

The thing that you are looking for to distinguish between assets is called localIdentifier property of PHAsset.

The Apple Docs define it as:

A unique string that persistently identifies the object. (read-only)

Sorry this answer will be a bit broad because I don't like your approach here.

If I were you, I'd do it like this:

First Create a Custom Class, let's name it PhotoInfo. (You don't really have to do this if you are not interested in keeping a lot of info about your photos. If that's the case, use the PFFetchResults of PHAssets directly if you want to. I will however go with CustomClass).

in PhotoInfo.h:

#import <Foundation/Foundation.h>
@interface PhotoInfo : NSObject

@property NSString *localIdentifier;

@end  

Now instead of using an array of images, use this custom class you created which will contain localIdentifier. Like this:

PhotoInfo *photo = [[PhotoInfo alloc] init];
photo.localIdentifier = asset.localIdentifier;

Let's say you want to fetch images from gallery, you would do something like this:

-(PHFetchResult*) getAssetsFromLibrary
{
    PHFetchResult *allPhotos;
    PHFetchOptions *allPhotosOptions = [[PHFetchOptions alloc] init];
    allPhotosOptions.sortDescriptors = @[[NSSortDescriptor sortDescriptorWithKey:@"creationDate" ascending:NO]]; //Get images sorted by creation date

    allPhotos = [PHAsset fetchAssetsWithMediaType:PHAssetMediaTypeImage options:allPhotosOptions];

    return allPhotos;
}

To populate your dataSource, you do something like:

NSMutableArray *yourPhotoDataSource = [[NSMutableArray alloc] init];
PHFetchResult * assets = [self getAssetsFromLibrary];
 for(PHAsset *asset in assets)
        {
            PhotoInfo *photo = [PhotoInfo new];
            photo.localIndentifier = asset.localIdentifier;
            [yourPhotoDataSource addObject:photo];

        }

Now let's say you have to display those images somewhere and you need an actual image for that so you will do something like this to get the image:

-(void) getImageForAsset: (PHAsset *) asset andTargetSize: (CGSize) targetSize andSuccessBlock:(void (^)(UIImage * photoObj))successBlock {
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        PHImageRequestOptions *requestOptions;

        requestOptions = [[PHImageRequestOptions alloc] init];
        requestOptions.resizeMode   = PHImageRequestOptionsResizeModeFast;
        requestOptions.deliveryMode = PHImageRequestOptionsDeliveryModeFastFormat;
        requestOptions.synchronous = true;
        PHImageManager *manager = [PHImageManager defaultManager];
        [manager requestImageForAsset:asset
                           targetSize:targetSize
                          contentMode:PHImageContentModeDefault
                              options:requestOptions
                        resultHandler:^void(UIImage *image, NSDictionary *info) {
                            @autoreleasepool {

                                if(image!=nil){
                                    successBlock(image);
                                }
                            }
                        }];
    });

}

Now let's say you are displaying those images in a tableView, in your cellForRowAtIndexPath, call the above mentioned method like this:

  //Show a spinner
  // Give a customizable size for image. Why load the memory with full image if you don't need to show it?
 [self getImageForAsset:asset andTargetSize:yourDesiredCGSizeOfImage andSuccessBlock:^(UIImage *photoObj) {
            dispatch_async(dispatch_get_main_queue(), ^{
                //Update UI of cell
                //Hide the spinner
                cell.thumbNail.image = photoObj;
            });
        }];

Now you are loading images asynchronously with smooth user Experience and saving memory as well by showing only the images which are needed instead of storing all of them. (You can make the performance even better by introducing caching but that's not the point here).

Finally getting to your question, to remove a certain image you will do only need the localIdentifier because it is unique for every PHAsset or Index.

Let's assume you are deleting some cell at your tableView which is showing that specific image which you now want to remove.

- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {

if (editingStyle == UITableViewCellEditingStyleDelete) {
    PhotoInfo *photo = [yourPhotoDataSource objectAtIndex:indexPath.row];
    [yourPhotoDataSource removeObject:photo];
    [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath]
                     withRowAnimation:UITableViewRowAnimationFade];


}
}

If you are not using a TableView/CollectionView and do not know the index of the object, you can use fast enumeration on your array but then you must know the localIdentifier of the object you wanna delete:

-(void) deletePhotoWithIdentifier:(NSString *) identifierStr{
NSMutableArray *dummyArray = [[NSMutableArray alloc] initWithArray:yourPhotoDataSource]; //created because we can't modify the array we are iterating on. Otherwise it crashes. 
[dummyArray enumerateObjectsWithOptions:NSEnumerationReverse usingBlock:^(PhotoInfo *p, NSUInteger index, BOOL *stop) {
    if ([p.localIndentifier isEqualToString:idenfierStr]) {
        [yourPhotoDataSource removeObjectAtIndex:index];
    }
}];

}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!