Почему не работает этот NSPredicate?

У меня есть массив MKAnnotation объектов с именем arrAnnotations. Я хочу выбрать одну из аннотаций с той же координатой, что и та, которая хранится в CLLocation объекте с именем «newLocation».

Я пытаюсь использовать NSPredicate, но это не работает.

NSPredicate *predicate = [NSPredicate  predicateWithFormat:@"(SELF.coordinate == %f)", newLocation.coordinate];
NSArray* filteredArray = [arrAnnotations filteredArrayUsingPredicate:predicate];
[self.mapView selectAnnotation:[filteredArray objectAtIndex:0] animated:YES];

FilterArray всегда содержит нулевые объекты.

Я также пробовал следующее, что тоже не работает

NSPredicate *predicate = [NSPredicate  predicateWithFormat:@"(coordinate == %f)", newLocation.coordinate];

и

NSPredicate *predicate = [NSPredicate  predicateWithFormat:@"(coordinate > 0)"];

и

NSPredicate *predicate = [NSPredicate  predicateWithFormat:@"(coordinate.latitude == %f)", newLocation.coordinate.latitude];

Последние два вызывают сбой приложения, третий - с NSInvalidArgumentException для [NSConcreteValue compare:], а четвертый, потому что latitude не соответствует кодированию "ключ-значение" (я предполагаю, что это потому, что координата - это просто c-struct, а не NSObject?).

Как я могу заставить это работать с NSPredicate? Может ли кто-нибудь дать мне ссылку на документ, который показывает, как работают предикаты изнутри? Я не понимаю, что они на самом деле делают, хотя я прочитал и понял большую часть Руководство по программированию предикатов. Является ли поиск в огромном массиве с помощью предикатов более эффективным, чем простой просмотр его с помощью конструкции for ... in? Если да / нет, то почему?


person avf    schedule 22.07.2010    source источник
comment
Вы не можете просто интерпретировать структуру как double. Вы можете получить что-то с NSLog(@"%f", aCoordinate), но это неопределенное поведение и может привести к сбоям и т. Д. Поскольку NSPredicate не работает с C-структурами, вы можете использовать явные тесты на данный момент, если кто-то с опытом работы с CoreLocation не знает лучшей альтернативы.   -  person Georg Fritzsche    schedule 22.07.2010


Ответы (1)


Свойство координат протокола MKAnnotation - это CLLocationCoordinate2D struct, поэтому он не допускается в синтаксисе формата NSPredicate в соответствии с Синтаксис строки формата предиката

Вместо этого вы можете использовать NSPredicate predicateWithBlock: для выполнения того, что вы пытаетесь сделать, но вы должны быть осторожны с CLLocationCoordinate2D и тем, как сравнивать его на равенство.

Свойство latitude и longitude CLLocationCoordinate2D: CLLocationDegrees, который по определению является double.

С помощью быстрого поиска вы можете найти несколько примеров проблем, с которыми вы можете столкнуться при сравнении значений с плавающей запятой на предмет равенства. Некоторые хорошие примеры можно найти здесь, здесь и здесь.

Учитывая все это, я считаю, что использование приведенного ниже кода для вашего предиката может решить вашу проблему.

NSPredicate *predicate = [NSPredicate predicateWithBlock:^BOOL(id evaluatedObject, NSDictionary *bindings) {

    id<MKAnnotation> annotation = evaluatedObject;

    if (fabsf([annotation coordinate].latitude - [newLocation coordinate].latitude) < 0.000001 
            && fabsf([annotation coordinate].longitude - [newLocation coordinate].longitude) < 0.000001) {
        return YES;
    } else {
        return NO;
    }

}];
person Felipe Sabino    schedule 30.06.2011