iOSGeek iOSGeek - 2 months ago 42x
Objective-C Question

How to compare PHAsset to UIImage

I have converted some


PHImageManager *manager = [PHImageManager defaultManager];
[manager requestImageForAsset:asset
resultHandler:^void(UIImage *image, NSDictionary *info) {
convertedImage = image;
[images addObject:convertedImage];

Now I want to do something like that:

[selectedAssets removeObject:image];

is an array of
is an

so I have implemented the isEqual like that:

- (BOOL)isEqual:(id)other {
if (other == self)
return YES;
if (!other || ![[other class] isEqual:[self class]])
return NO;

NSData *data1 = UIImagePNGRepresentation(self.image);
NSData *data2 = UIImagePNGRepresentation(((TINSelectedImage*)other).image);

return [data1 isEqual:data2];

But it does not work !


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;


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
                        resultHandler:^void(UIImage *image, NSDictionary *info) {
                            @autoreleasepool {



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]


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