Objective c NSFetchRequest和predicateWithBlock

Objective c NSFetchRequest和predicateWithBlock,objective-c,core-data,nsfetchedresultscontroller,nsfetchrequest,Objective C,Core Data,Nsfetchedresultscontroller,Nsfetchrequest,我正在玩一个应用程序,它使用核心数据和NSManagedObjects来填充UITableView。在我的应用程序中只有一个类,叫做事件。我已在事件上创建了以下自定义实例方法: - (BOOL)isExpired { return ([[self.endOn dateAtEndOfDay] timeIntervalSinceNow] < 0); } 但我得到了错误:***由于未捕获的异常“NSInvalidArgumentException”而终止应用程序,原因是:“subpre

我正在玩一个应用程序,它使用核心数据和NSManagedObjects来填充UITableView。在我的应用程序中只有一个类,叫做
事件
。我已在
事件
上创建了以下自定义实例方法:

- (BOOL)isExpired {
    return ([[self.endOn dateAtEndOfDay] timeIntervalSinceNow] < 0);
}
但我得到了错误:
***由于未捕获的异常“NSInvalidArgumentException”而终止应用程序,原因是:“subpredicate BLOCKPREDICATE(0x272ac)存在问题”
***
。这是否意味着不能将块谓词用于NSFETCH请求?还是我只是做得不恰当


谢谢大家!

因此,我们似乎已经在原始帖子的评论中确定,这可能是由于SQLite存储与块谓词不兼容造成的,因为核心数据无法将它们转换为SQL以在存储中运行(感谢JoostK)

有几种方法可以克服这一问题:

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

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

NSArray *allEvents = [context executeFetchRequest:fetchRequest];

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

NSArray *expiredEvents = [allEvents filteredArrayUsingPredicate:predicate];

我注意到,
predicateWithBlock
的文档声明“在Mac OS X v10.6中,核心数据在内存和原子存储中支持此方法,但在基于SQLite的存储中不支持此方法。”但没有说明这是否/如何影响iOS(您的场景)。您没有碰巧运行SQLite存储,因此这可能会影响您?@ig2r这实际上是问题的答案。是的,iOS也是如此。原子存储将被打开并读取,您将拥有所有已创建的
NSManagedObject
s,因此您可以向它们调用消息。内存存储也一样。但对于SQLite,
NSManagedObject
s仅在存储请求时创建。SQLite
SELECT
语句将基于获取请求创建,并考虑谓词。因此,谓词在对象创建之前就已经应用了,因此您不能对它们调用消息。@ig2r&Joost您能在文档中提到它的位置吗?我有一个无法避免使用predicateWithBlock创建FetchedResultsController的情况。那么,如果不是使用谓词,这是如何实现的呢?(很抱歉,我是新手,所以不会让我在评论中做出回应)但我们不能将此两步技术用于NSFetchedResultsController,对吗?Exactlt Martin,关键是您可以使用
NSFetchedResultsController
的任何好处,比如方法委派
NSArray *allEvents = [context executeFetchRequest:fetchRequest];

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

NSArray *expiredEvents = [allEvents filteredArrayUsingPredicate:predicate];