问题
I have converted some PHAsset
to UIImage
:
PHImageManager *manager = [PHImageManager defaultManager];
[manager requestImageForAsset:asset
targetSize:PHImageManagerMaximumSize
contentMode:PHImageContentModeDefault
options:requestOptions
resultHandler:^void(UIImage *image, NSDictionary *info) {
convertedImage = image;
[images addObject:convertedImage];
}];
Now I want to do something like that:
[selectedAssets removeObject:image];
where selectedAssets
is an array of PHAsset
and image
is an UIImage
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 !
回答1:
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];
}
}];
}
来源:https://stackoverflow.com/questions/38829187/how-to-compare-phasset-to-uiimage