Как получить управляемые объекты, отсортированные по вычисленному значению - PullRequest
4 голосов
/ 07 мая 2010

Я работаю над приложением, которое использует CoreData. Существует объект местоположения, который содержит значения широты и долготы. Я хотел бы получить эти объекты, отсортированные по расстоянию до местоположения пользователя. Я попытался установить дескриптор сортировки для формулы расстояния sqrt ((x1 - x2) ^ 2 + (y1 - y2) ^ 2), но он завершился ошибкой, за исключением «... keypath ... not found in entity».

NSString *distanceFormula = [NSString stringWithFormat:@"sqrt(((latitude - %f) * (latitude - %f)) + ((longitude - %f) * (longitude - %f)))", 
                            location.coordinate.latitude, 
                            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];

Я бы хотел получить уже отсортированные объекты, а не получить их все, а затем отсортировать в коде.

Любые советы приветствуются.

1 Ответ

5 голосов
/ 07 мая 2010

NSSortDescriptor следует инициализировать ключевой строкой для свойства объекта, а не строкой запроса.Это означает, что вы должны реализовать формулу расстояния как метод вашего объекта.

После этого не имеет значения, выполняете ли вы сортировку до или после извлечения:

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

Еще,Ваша формула расстояния не работает правильно, как лат.и долго.не иметь такого же масштаба, если вы не на экваторе.Используйте это:

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

Если расстояние превышает несколько сотен километров, вам нужен Закон сферических косинусов :

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