NSFetchRequest и ПредикатWithBlock - PullRequest
25 голосов
/ 23 августа 2010

Я играю с приложением, которое использует Core Data и NSManagedObjects для заполнения UITableView.В моем приложении есть только один класс, который называется Event.Я создал следующий пользовательский метод экземпляра для Event:

- (BOOL)isExpired {
    return ([[self.endOn dateAtEndOfDay] timeIntervalSinceNow] < 0);
}

Я хотел бы ограничить UITableView, который отображает Event объектов, только событиями, срок действия которых истек - то есть где isExpired возвращает YES.Я попытался сделать это, добавив NSPredicate к NSFetchRequest:

NSPredicate *predicate = [NSPredicate predicateWithBlock:^BOOL(id evaluatedObject, NSDictionary * bindings) {return([evaluatedObject isExpired]);}];
[fetchRequest setPredicate:predicate];

, но я получаю ошибку: *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Problem with subpredicate BLOCKPREDICATE(0x272ac)' ***.Означает ли это, что вы не можете использовать блочный предикат с NSFetchRequest?Или я просто неправильно его сконструировал?

Спасибо!

Ответы [ 2 ]

24 голосов
/ 23 августа 2010

Итак, похоже, что мы установили в комментариях к исходному сообщению, что это, вероятно, вызвано тем, что хранилища SQLite несовместимы с блочными предикатами, поскольку Core Data не может преобразовать их в SQL для запуска их в хранилище (спасибо,JoostK).

Может быть несколько способов преодолеть это:

  • При условии, что дата окончания ваших сущностей является обычным атрибутом, вы можете выразить срок действияограничение в виде строки формата предиката вместо предиката блока, который Core Data должен иметь возможность преобразовать в предложение SQL.
  • Если вышеизложенное возможно, вы, вероятно, предпочтете использовать шаблон запроса fetch для извлечения просроченных предметов.Однако вам потребуется передать переменную подстановки, например $NOW, чтобы получить доступ к текущей дате.Преимущество этого заключается в том, что шаблон предиката отображается в редакторе моделей.
  • Однако оба подхода имеют недостаток, заключающийся в дублировании существующей функциональности (т. Е. Вашего метода isExpired).Таким образом, другим способом было бы сначала извлечь все подходящие объекты независимо от их состояния истечения, а затем выполнить выделенный шаг фильтрации на результирующем наборе объектов, чтобы отсеять не просроченные объекты.Поскольку к тому моменту они были полностью воскрешены из магазина, вы сможете использовать для этого предикат блока.
7 голосов
/ 15 июня 2011

Вы можете выполнить обычный запрос на выборку без указания предиката, а затем отфильтровать полученный массив:

NSArray *allEvents = [context executeFetchRequest:fetchRequest];

if (!allEvents) { // do error handling here
}

NSArray *expiredEvents = [allEvents filteredArrayUsingPredicate:predicate];
...