Reputation: 10410
I'm using the Photos framework (aka PhotoKit
). In my app I need to gather Moments (which are of type PHAssetCollection
). PHAssetCollection
has a property of CLLocation *approximateLocation
.
However I cannot get the NSPredicate
to work when I retrieve the Moments from PhotoKit.
-(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.
Upvotes: 7
Views: 628
Reputation: 1305
If you look at Table 1 of the PHFetchOptions documentation, you will see that you can only use the following keys for predicate filtering of PHAssetCollections:
SELF
localIdentifier
localizedTitle (or title)
startDate
endDate
estimatedAssetCount
if you want to filter a PHCollection (as opposed to an PHAssetCollection), then you are limited to the following keys:
SELF
localIdentifier
localizedTitle (or title)
startDate
endDate
Nothing resembling "approximateLocation" is a support key. But wait! The localizedTitle is generally a place name. Have not seen it otherwise. So, you might be able to get assets by predicate filtering moment collections
Upvotes: 0