NSFetchRequest 和 predicateWithBlock

Posted

技术标签:

【中文标题】NSFetchRequest 和 predicateWithBlock【英文标题】:NSFetchRequest and predicateWithBlock 【发布时间】:2010-08-22 20:22:26 【问题描述】:

我正在玩一个使用 Core Data 和 NSManagedObjects 来填充 UITableView 的应用程序。我的应用程序中只有一个类,称为Event。我在Event 上创建了以下自定义实例方法:

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

我想将显示Event 对象的UITableView 限制为仅显示过期的事件——即isExpired 返回YES。我试图通过在NSFetchRequest 中添加NSPredicate 来做到这一点:

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 一起使用?还是我构造不当?

谢谢!

【问题讨论】:

我注意到predicateWithBlock 的文档指出“在 Mac OS X v10.6 中,Core Data 在内存和原子存储中支持此方法,但在基于 SQLite 的存储中不支持。”不过,没有关于这是否/如何影响 ios(您的场景)的消息。您不会碰巧经营 SQLite 商店,因此这可能会影响到您? @ig2r 这实际上是问题的答案。是的,iOS 也是如此。将打开并读取原子存储,您将创建所有 NSManagedObjects,因此您可以向它们调用消息。内存存储也是如此。但是对于 SQLite,NSManagedObjects 仅在商店有请求时创建。将基于获取请求创建 SQLite SELECT 语句,同时考虑谓词。所以谓词在对象创建之前就已经应用了,因此你不能在它们上调用消息。 @ig2r & Joost 你能在文档中这样提到它的地方找到吗?我有一种情况,我无法避免使用 predicateWithBlock 创建 FetchedResultsController。 【参考方案1】:

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

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

假设您的实体的结束日期是一个常规属性,您可能能够将到期约束表示为谓词格式字符串而不是块谓词,Core Data 应该能够将其转换为 SQL 子句。 如果上述情况可行,您可能更喜欢使用fetch request template 来检索过期项目。不过,您需要传入一个像 $NOW 这样的替换变量才能访问当前日期。这具有使谓词模板显示在模型编辑器中的优势。 但是,这两种方法都有重复现有功能的缺点(即您的 isExpired 方法)。因此,另一种方法是首先获取所有符合条件的实体,而不管它们的到期状态如何,然后对结果实体集运行专门的过滤步骤以清除未到期的实体。由于此时它们已完全从商店中复活,因此您应该可以为此使用块谓词。

【讨论】:

那么,如果不使用谓词,这又是如何实现的呢? (对不起,我是新人,所以它不会让我在 cmets 中回复)【参考方案2】:

您可以在不指定谓词的情况下执行正常的 fetch 请求,然后过滤结果数组:

NSArray *allEvents = [context executeFetchRequest:fetchRequest];

if (!allEvents)  // do error handling here


NSArray *expiredEvents = [allEvents filteredArrayUsingPredicate:predicate];

【讨论】:

但我们不能将这种两步技术与 NSFetchedResultsController 一起使用,对吧? Exactlt Martin,重点是您可以使用NSFetchedResultsController 的任何好处,例如方法委托

以上是关于NSFetchRequest 和 predicateWithBlock的主要内容,如果未能解决你的问题,请参考以下文章

NSFetchRequest / 谓词问题

NSFetchRequest 和 predicateWithBlock

嵌套 NSFetchRequest?

MonoTouch 支持 NSFetchRequest 和 NSPredicate

NSFetchRequest - 通过关系获取所有对象

iPhone 核心数据:具有不同属性和字母部分的 NSFetchRequest