NSFetchRequest和predicateWithBlock

时间:2010-08-22 20:22:27

标签: objective-c core-data nsfetchedresultscontroller nsfetchrequest

我正在使用一个使用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 个答案:

答案 0 :(得分:23)

所以,看来我们在原帖的评论中已经确定这可能是由于SQLite存储与块谓词不兼容造成的,因为Core Data无法将这些转换为SQL来在商店中运行它们(谢谢, JoostK)。

可能有几种方法可以解决这个问题:

  • 如果实体的结束日期是常规属性,您可以将过期约束表示为谓词格式字符串而不是块谓词,核心数据应该能够转换为SQL子句。< / LI>
  • 如果上述情况可能,您可能更愿意使用fetch request template来检索过期的项目。但是,您需要传递一个替换变量,如$NOW,以便访问当前日期。这样做的好处是可以在模型编辑器中显示谓词模板。
  • 但是,这两种方法都存在重复现有功能(即isExpired方法)的缺点。因此,另一种方法是首先获取所有合格实体而不管其到期状态,然后对生成的实体集执行专用过滤步骤以清除未过期的实体。从那时起,它们已经从商店完全复活,你应该可以使用块谓词。

答案 1 :(得分:7)

您可以在不指定谓词的情况下执行常规提取请求,然后过滤生成的数组:

NSArray *allEvents = [context executeFetchRequest:fetchRequest];

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

NSArray *expiredEvents = [allEvents filteredArrayUsingPredicate:predicate];