Почему не работает этот NSP-предикат? - PullRequest
1 голос
/ 22 июля 2010

У меня есть массив 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? Может кто-нибудь дать мне ссылку на документ, который показывает, как предикаты работают под капотом? Я не понимаю, что они на самом деле делают, хотя я прочитал и понял большую часть Руководства по программированию предикатов от Apple *1030*. Является ли поиск в огромном массиве с предикатами более эффективным, чем просто цикл по нему с помощью конструкции for ... in? Если да / нет, почему?

1 Ответ

6 голосов
/ 30 июня 2011

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

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

Свойство

CLLocationCoordinate2D latitude и longitude имеет тип 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;
    }

}];
...