mardi 5 mai 2015

Filter PHAssetCollections within radius of CLLocationCoordinate2d

I'm using the Photos framework (aka PhotoKit). In my app I need to gather Moments (which are of type PHAssetCollection). PHAssetCollection has CLLocation *approximateLocation.

However I cannot get the NSPredicate to work.

-(void)getMomentsNearCoordinate:(CLLocationCoordinate2D)coordinate completionBlock:(PKAssetManagerArrayBlock)completionBlock{
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        PHFetchOptions *options = [[PHFetchOptions alloc] init];
        options.predicate = [NSPredicate predicateWithFormat:@"approximateLocation.coordinate.latitude < 37.0"];

        self.moments = [PHAssetCollection fetchMomentsWithOptions:options];

        // Convert PHCollection into NSArray
        NSMutableArray *momentsArray = [[NSMutableArray alloc]initWithCapacity:self.moments.count];
        [self.moments enumerateObjectsUsingBlock:^(PHAssetCollection *moment, NSUInteger idx, BOOL *stop) {
            [momentsArray addObject:moment];
        }];

        dispatch_async(dispatch_get_main_queue(), ^{
            completionBlock([NSArray arrayWithArray:momentsArray]);
        });
    });
}

The debugger will stop on

self.moments = [PHAssetCollection fetchMomentsWithOptions:options];

with the error:

*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Unsupported predicate in fetch options: approximateLocation.coordinate.latitude < 37'

This seems strange since I can use NSPredicate to filter by startDate or endDate.

Anyhow, next I thought I'd try the NSPredicate with block:

-(void)getMomentsNearCoordinate:(CLLocationCoordinate2D)coordinate completionBlock:(PKAssetManagerArrayBlock)completionBlock{
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        PHFetchOptions *options = [[PHFetchOptions alloc] init];
        options.predicate = [NSPredicate predicateWithBlock:^BOOL(id evaluatedObject, NSDictionary *bindings) {
            // Logic goes here
            return YES;
        }];

        self.moments = [PHAssetCollection fetchMomentsWithOptions:options];

        // Convert PHCollection into NSArray
        NSMutableArray *momentsArray = [[NSMutableArray alloc]initWithCapacity:self.moments.count];
        [self.moments enumerateObjectsUsingBlock:^(PHAssetCollection *moment, NSUInteger idx, BOOL *stop) {
            [momentsArray addObject:moment];
        }];
        dispatch_async(dispatch_get_main_queue(), ^{
            completionBlock([NSArray arrayWithArray:momentsArray]);
        });
    });
}

Again the debugger stops at

self.moments = [PHAssetCollection fetchMomentsWithOptions:options];

with a different error message:

*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Unsupported predicate in fetch options: BLOCKPREDICATE(0x27d338)'

Finally I remembered reading in CloudKit documentation that they added a new support for filtering by distance. However this is for CKQuery, not NSPredicate. I decided to give it a try anyhow. I use my coordinate to make a CLLocation then call:

-(void)getMomentsNearLocation:(CLLocation*)location completionBlock:(PKAssetManagerArrayBlock)completionBlock{
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        PHFetchOptions *options = [[PHFetchOptions alloc] init];
        options.predicate = [NSPredicate predicateWithFormat:@"distanceToLocation:fromLocation:(%K,%@) < %f",
                             location,
                             2.0];

        self.moments = [PHAssetCollection fetchMomentsWithOptions:options];

        // Convert PHCollection into NSArray
        NSMutableArray *momentsArray = [[NSMutableArray alloc]initWithCapacity:self.moments.count];
        [self.moments enumerateObjectsUsingBlock:^(PHAssetCollection *moment, NSUInteger idx, BOOL *stop) {
            [momentsArray addObject:moment];
        }];
        dispatch_async(dispatch_get_main_queue(), ^{
            completionBlock([NSArray arrayWithArray:momentsArray]);
        });
    });
}

You guessed it. Error:

*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[CLLocation rangeOfString:]: unrecognized selector sent to instance 0x19e3e350'

In the mean time I'll just iterate through the list of PHAssetCollections and manually calculate if it's near the CLLocation. This will be far less efficient.

Aucun commentaire:

Enregistrer un commentaire