Search code examples
iosobjective-cphotokit

PHFetchResult custom sorting: items ordered by day, oldest photos first


I am willing to order my results by day so that the oldest photos are displayed on top.

I am currently fetching photos using the PHAsset fetchAssetsWithMediaType:

@property PHFetchResult *photos;

self.photos = [PHAsset fetchAssetsWithMediaType:PHAssetMediaTypeImage options:nil];

Ideally I want the results ordered by day, oldest photos first. Like this:

[11 Dec]
Photo #20 with creation time 17:00
Photo #21 with creation time 18:30
Photo #22 with creation time 19:00
Photo #23 with creation time 20:40
Photo #24 with creation time 21:00
[10 Dec]
Photo #16 with creation time 10:30
Photo #17 with creation time 11:00
Photo #18 with creation time 12:20
Photo #19 with creation time 13:00
[9 Dec]
Photo #14 with creation time 16:30
Photo #15 with creation time 17:00

I have seen I can pass a PHFetchOptions object with a predicate and some sort descriptors ( https://developer.apple.com/reference/photos/phfetchoptions ), can you suggest me how to specify them (I believe I should sort them using the creationDate attribute) so that I'll get the desired order?


Solution

  • PHFetchOptions accepts sortDescriptors, however it ignores custom comparisons (i believe since it simply does an SQL query) as written here (https://developer.apple.com/reference/photos/phfetchoptions/1624771-sortdescriptors):

    Photos does not support sort descriptors created with the sortDescriptorWithKey:ascending:comparator: method.

    The answer is that you should move the results in a new NSArray and then order them after fetching them:

    - (void)loadPhotos
    {
        PHFetchResult *photosResult = [PHAsset fetchAssetsWithMediaType:PHAssetMediaTypeImage options:nil];
    
        self.photos = [@[] mutableCopy];
        for(PHAsset *asset in photosResult){
            [self.photos addObject:asset];
        }
        [self.photos sortUsingDescriptors:@[[NSSortDescriptor sortDescriptorWithKey:@"creationDate"
                                                                          ascending:YES
                                                                         comparator:^NSComparisonResult(NSDate *dateTime1, NSDate *dateTime2) {
                                                                             unsigned int flags = NSCalendarUnitYear | NSCalendarUnitMonth | NSCalendarUnitDay;
                                                                             NSCalendar* calendar = [NSCalendar currentCalendar];
    
                                                                             NSDateComponents* components1 = [calendar components:flags fromDate:dateTime1];
                                                                             NSDate* date1 = [calendar dateFromComponents:components1];
    
                                                                             NSDateComponents* components2 = [calendar components:flags fromDate:dateTime2];
                                                                             NSDate* date2 = [calendar dateFromComponents:components2];
    
                                                                             NSComparisonResult comparedDates = [date1 compare:date2];
                                                                             if(comparedDates == NSOrderedSame)
                                                                             {
                                                                                 return [dateTime2 compare:dateTime1];
                                                                             }
                                                                             return comparedDates;
                                                                         }
                                             ]]];
    
    }
    

    I didn't tested this solution with a huge camera roll (sorting here is done in memory and it can be a performance bottleneck), but I hope this can help.