NSPredicate для поиска по нескольким словам

В моем приложении iOS у меня есть очень простой предикат для моего контроллера выборки.

NSString *format = [NSString stringWithFormat:@"name like[c] '%@'", nameVar];
NSPredicate *predicate = [NSPredicate predicateWithFormat:format];
[fetchController setPredicate:predicate];

Он выполняет базовый поиск имени без учета регистра. Теперь я хотел бы изменить его, чтобы я мог поместить несколько слов в поле поиска (nameVar имеет значение из окна поиска), разделенных пробелами, и предикат отфильтровал результаты, соответствующие всем этим ключевым словам.

Итак, если у меня есть два имени: «Джон Смит» и «Мэри Смит», и я ищу: «Смит М», я хотел бы получить только один результат, но такой поиск: «Sm th ith» должен возвращать оба значения.

У кого-нибудь есть идеи, как это должно быть реализовано?


person RaYell    schedule 14.02.2011    source источник


Ответы (1)


редактировать обратно на обычном компьютере...

Итак, есть пара вещей, о которых нужно знать:

  1. Вам не нужно заключать в кавычки местозаполнитель замены в строке формата. Когда метод строит предикат, он будет создавать абстрактное синтаксическое дерево объектов NSExpression и NSPredicate (в частности, NSComparisonPredicate и NSCompoundPredicate). Ваша строка будет помещена в NSExpression типа NSConstantValueExpressionType, что означает, что она уже будет интерпретироваться как обычная строка. Помещение одинарных кавычек в строку формата фактически сделает ваш предикат нефункциональным.
  2. Вы не ограничены одним сравнением в предикате. Судя по всему, вы хотите иметь столько сравнений, сколько «слов» в строке поиска (nameVar). В этом случае мы разобьем nameVar на составляющие слова и создадим сравнение для каждого слова. Как только мы это сделали, мы AND объединяем их вместе, чтобы создать единый всеобъемлющий предикат. Код ниже делает именно это.

исходный ответ

Вы можете сделать это, создав собственный NSCompoundPredicate:

NSString *nameVar = ...; //ex: smith m
NSArray *names = ...; //ex: John Smith, Mary Smith

NSArray *terms = [nameVar componentsSeparatedByCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
NSMutableArray *subpredicates = [NSMutableArray array];

for(NSString *term in terms) {
  if([term length] == 0) { continue; }
  NSPredicate *p = [NSPredicate predicateWithFormat:@"name contains[cd] %@", term];
  [subpredicates addObject:p];
}

NSPredicate *filter = [NSCompoundPredicate andPredicateWithSubpredicates:subpredicates];
[fetchController setPredicate:filter];

Предупреждение: набрано в браузере на моем iPhone.

person Dave DeLong    schedule 14.02.2011
comment
Итак, после запуска этого кода, где я могу найти свои результаты? подпредикаты? Я новичок в iOS-разработке, извините, если вопрос глупый :) - person Boris Nikolic; 18.10.2015