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 也是如此。将打开并读取原子存储,您将创建所有 NSManagedObject
s,因此您可以向它们调用消息。内存存储也是如此。但是对于 SQLite,NSManagedObject
s 仅在商店有请求时创建。将基于获取请求创建 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 和 predicateWithBlock