How do I determine if a PHAsset in a PHFetchResult represents a deleted photo?

Ziewvater picture Ziewvater · Sep 23, 2014 · Viewed 9k times · Source

I'm trying to grab a thumbnail of the last photo taken on a device using the new Photos framework in iOS 8. The code I have right now to do this is the following:

PHFetchOptions *fetchOptions = [PHFetchOptions new];
fetchOptions.sortDescriptors = @[[NSSortDescriptor sortDescriptorWithKey:@"creationDate" ascending:NO]];
PHFetchResult *assetsInfo = [PHAsset fetchAssetsWithOptions:fetchOptions];

PHImageRequestOptions *requestOptions = [PHImageRequestOptions new];
requestOptions.version = PHImageRequestOptionsVersionCurrent;
requestOptions.deliveryMode = PHImageRequestOptionsDeliveryModeFastFormat;
[[PHImageManager defaultManager] requestImageForAsset:[assetsInfo objectAtIndex:1]
                                           targetSize:CGSizeMake(100, 100)
                                          contentMode:PHImageContentModeAspectFill
                                              options:requestOptions
                                        resultHandler:^(UIImage *result, NSDictionary *info) {
                                            if (result) {
                                                // galleryButton is just a UIButton in the view
                                                [galleryButton setImage:result forState:UIControlStateNormal];
                                            }
                                        }];

The code manages to grab the most recently taken photo on the device, but if the last photo taken on the device was deleted, that fact isn't taken into account, and the button's image is set to the deleted photo in the resultHandler. This seems to be caused by the fact that in iOS 8, when you delete a photo it takes 30 days before it's actually removed from the device, and for some reason these photos are still included in the PHFetchResults.

I've tried to look for a "deleted" or similar attribute on the PHAsset objects included in assetsInfo, but I couldn't find any kind of information. The printout of the deleted photo in the debugger looks like this:

<PHAsset: 0x57462a0> 7689FC1C-9EE2-4FF7-9B37-4A032A3FDA01/L0/001 mediaType=1/0, assetSource=2, (1536x2048), creationDate=2014-09-22 06:45:10 +0000, location=1, hidden=0, favorite=0

The printout for the next object in assetsInfo, a photo I verified was not deleted, looks like this:

<PHAsset: 0x57461a0> E48D1482-395B-405C-85F9-FFD04D9EBFBD/L0/001 mediaType=1/0, assetSource=3, (2448x3264), creationDate=2014-09-21 04:24:55 +0000, location=0, hidden=0, favorite=0

There doesn't seem to be any information there that can tell me if the photo was deleted. I thought perhaps the hidden attribute would help, but instead it's something to do with whether or not the photo shows up in particular Photos.app albums/collections. I thought that maybe the assetSource attribute might be of use, but it doesn't seem to be documented, and upon further investigation also doesn't seem to be related to the deleted status of the photo.

Is there a way to see if a PHAsset object represents a deleted photo? Is there a way to narrow down the assets I'm fetching to exclude the photos contained in the "Recently Deleted" album?

Answer

gabbler picture gabbler · Oct 3, 2014
PHFetchResult *fetchResults = [PHAsset fetchAssetsWithOptions:options];
NSArray* tempArray = [fetchResults objectsAtIndexes:[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, fetchResults.count)]];
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"description contains %@",@"assetSource=3"];
NSArray *filteredArray =  [tempArray filteredArrayUsingPredicate:predicate];

The filteredArray doesn't include the "Recently Deleted" album and doesn't have identical looking photos. Also for the deleted photo asset in your assetsInfo, the following two will return NO.

[asset canPerformEditOperation:PHAssetEditOperationContent] 
[asset canPerformEditOperation:PHAssetEditOperationProperties]

In PHAsset Runtime Headers there are useful properties:

@property (getter=isTrashed, nonatomic, readonly) bool trashed;
@property (nonatomic, readonly) NSDate *trashedDate;