开发者

How to fetch managed objects sorted by calculated value

开发者 https://www.devze.com 2022-12-29 18:38 出处:网络
I\'m working on the app that uses CoreData. There is location entity that holds latitude and longitude values. I\'d like to fetch those entities sorted by distance to the user\'s location.

I'm working on the app that uses CoreData. There is location entity that holds latitude and longitude values. I'd like to fetch those entities sorted by distance to the user's location. I tried to set sort descriptor to distance formula sqrt ((x1 - x2)^2 + (y1 - y2)^2) but it fails with exception "... keypath ... not found in entity".

NSString *distanceFormula = [NSString stringWithFormat:@"sqrt(((latitude - %f) * (latitude - %f)) + ((longitude - %f) * (longitude - %f)))", 
                            location.coordinate.开发者_如何学Golatitude, 
                            location.coordinate.latitude, 
                            location.coordinate.longitude, 
                            location.coordinate.longitude];
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:distanceFormula ascending:YES];
[fetchRequest setSortDescriptors:[NSArray arrayWithObject:sortDescriptor]];
NSError *error;
NSArray *result = [[self managedObjectContext] executeFetchRequest:fetchRequest error:&error];

I'd like to fetch already sorted objects rather then fetch them all and then sort in the code.

Any tips appreciated.


NSSortDescriptor should be initialised with a key string for a property of the object, not a query string. It means you should implement your distance formula as a method of your object.

After doing so, it doesn't really matter if you sort before or after fetching:

NSArray *result = [[self managedObjectContext] executeFetchRequest:fetchRequest error:&error];
result = [result sortedArrayUsingSelector:@"compareDistance"];

Another point. Your distance formula doesn't work correctly, as lat. and long. don't have the same scale, unless you're on the equator. Use this:

double latDiff = lat1-lat2;
double longDiff = (long1-long2)*cos(lat1); //cos() assumes lat1 is in radians
double distance = sqrt(latDiff*latDiff+longDiff*longDiff);

If the distance is more than a few hundred kilometers, you need Spherical cosines law:

// assuming angles in radian,
double separation = acos( sin(lat1)*sin(lat2) + cos(lat1)*cos(lat2)*cos(long1-long2) );
double distance = separation*earthRadius;
0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号