问题
I have a list of geographical locations in Core Data (entity name is "Stops").
I want to sort them by the current location, so I can show the user which locations are nearby. I'm using an NSFetchedResultsController so that the results can be easily displayed in a UITableView.
I am using the following code to attempt this sort:
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"stop_lat" ascending:YES comparator:^NSComparisonResult(Stops *obj1, Stops *obj2) {
CLLocation *currentLocation = locationManager.location;
CLLocation *obj1Location = [[CLLocation alloc]initWithLatitude:[obj1.stop_lat doubleValue] longitude:[obj1.stop_lon doubleValue]];
CLLocation *obj2Location = [[CLLocation alloc]initWithLatitude:[obj2.stop_lat doubleValue] longitude:[obj2.stop_lon doubleValue]];
CLLocationDistance obj1Distance = [obj1Location distanceFromLocation:currentLocation];
CLLocationDistance obj2Distance = [obj2Location distanceFromLocation:currentLocation];
NSLog(@"Comparing %@ to %@.\n Obj1 Distance: %f\n Obj2 Distance: %f",obj1.stop_name, obj2.stop_name, obj1Distance, obj2Distance);
if (obj1Distance > obj2Distance) {
return (NSComparisonResult)NSOrderedDescending;
}
if (obj1Distance < obj2Distance) {
return (NSComparisonResult)NSOrderedAscending;
}
return (NSComparisonResult)NSOrderedSame;
}];
NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor, nil];
[fetchRequest setSortDescriptors:sortDescriptors];
[fetchRequest setEntity:[NSEntityDescription entityForName:[Stops entityName] inManagedObjectContext:context]];
frcNearby = [[NSFetchedResultsController alloc]
initWithFetchRequest:fetchRequest
managedObjectContext:context
sectionNameKeyPath:nil
cacheName:nil];
NSError *error;
BOOL success = [frcNearby performFetch:&error];
if (error) NSLog(@"ERROR: %@ %@", error, [error userInfo]);
However, my NSFetchedResultsController is just returning all of my items sorted by the key I specified ("stop_lat") rather than sorted by the user's current location.
It looks like my comparator block isn't ever getting called, because the NSLog in there never prints.
What am I missing here?
回答1:
Objective-C based sort descriptors cannot be used with a fetch request.
From the "Core Data Programming Guide":
... To summarize, though, if you execute a fetch directly, you should typically not add Objective-C-based predicates or sort descriptors to the fetch request. Instead you should apply these to the results of the fetch.
回答2:
A different take on this would be to have a property on your 'Stop' managedObject called meanSquared (probably an NSDecimalNumber).
When your device lat/long has moved sufficiently to alter the 'nearest Stop' data, then you update all 'Stop' objects with the meanSquared distance (i.e. (yourLat-stopLat)^2+(yourLong-stopLong)^2), then just use 'meanSquared' in your sortDescriptor.
Depending on the number of times that you update the user's position, the distance between stops and the number of stops this might be an optimal solution.
回答3:
You can't sort by lat/Lon anyway, you'll need to compute distance for each point and sort by that. Or fetch a range of lat/Lon values near the user, fetch that subset, compute distance for them and display. range would be like user's lat +/- 0.1 degrees, etc for the fetch.
回答4:
I would recommend the following approach:
See the 'Geo-Location Predicate' section of http://www.objc.io/issue-4/core-data-fetch-requests.html
It gets approximate results using a predicate and then sorts them accurately in-memory.
来源:https://stackoverflow.com/questions/12027769/nssortdescriptor-sort-by-location