带有谓词的 NSFetchedResultsController 忽略从不同 NSManagedObjectContext 合并的更改

Posted

技术标签:

【中文标题】带有谓词的 NSFetchedResultsController 忽略从不同 NSManagedObjectContext 合并的更改【英文标题】:NSFetchedResultsController with predicate ignores changes merged from different NSManagedObjectContext 【发布时间】:2010-10-13 12:53:46 【问题描述】:

我正在使用 NSFetchedResultsController 呈现表格视图内容,它有一个谓词:

[NSPredicate predicateWithFormat:@"visible == %@", [NSNumber numberWithBool:YES]]

在使用单独的NSManagedObjectContext 的后台线程上,我更新了一些实体并将它们的visible 值从NO 更改为YES。在主线程的NSManagedObjectContext 中保存、合并更改。但是NSFetchedResultsControllerfetchedObjects 不会改变。控制器也不会在委托上调用-controller:didChangeObject:...。如果实体以相同的方式在主线程上更新(我的测试应用程序调用相同的方法),一切都会按预期工作。

Notification 的NSUpdatedObjectsKey 也包含这些对象。

目前我发现的唯一解决方案是调用每个 NSUpdatedObjectsKey 实体:

NSManagedObjectContext *context = ... // main thread context
[context existingObjectWithID:[object objectID] error:nil]

此问题仅适用于以前与谓词不匹配的更新对象。

我是否遗漏了一些明显的东西?

【问题讨论】:

不是Core Data的bug吗?我认为我们应该向 Apple 提交错误报告。我刚做了一个。 错误?如果有,有什么进展吗? ios 10 终于修复了这个 bug:twitter.com/an0/status/750413478620491776 【参考方案1】:

事实证明,主 NSManagedObjectContext 没有为更新的对象触发 NSManagedObjectContextObjectsDidChangeNotification 事件,因为它不是针对故障对象完成的。

通用修复(或跟踪需要此处理的对象 ID):

NSManagedObjectContext *context = [self managedObjectContext];
for(NSManagedObject *object in [[notification userInfo] objectForKey:NSUpdatedObjectsKey]) 
  [[context objectWithID:[object objectID]] willAccessValueForKey:nil];


[context mergeChangesFromContextDidSaveNotification:notification];

来自NSManagedObject Class Reference:

您可以使用 nil 的键值,以确保一个 故障已被触发,如图所示 通过以下示例。

【讨论】:

这为我节省了很多时间。我对此赞不绝口。谢谢。 哇我也一样。在这上面浪费了几个小时! 听起来你正在后台线程上进行合并。更改的合并需要在主/UI 线程上完成,才能正确触发事件。如果您使用的是父/子 MOC,因为它们在内部处理这些通知,这是没有实际意义的。 不,我所有的更改和合并都发生在主线程上。明天我将使用雷达创建一个示例项目。 使用 MagicalRecord,我似乎遇到了同样的问题。但是上面的修复对我不起作用。我确实在后台上下文(线程)上有我的 FRC,但我没有看到任何变化。【参考方案2】:

在合并来自其他 NSManagedObjectContext 的更改后,您必须在 Background-NSManagedObjectContext 上调用 processPendingChanges

参见 CoreData 编程指南:

请注意,更改通知是在 NSManagedObjectContext 的 processPendingChanges 方法。主线程绑定到事件中 应用程序的循环,以便调用 processPendingChanges 在主拥有的上下文上的每个用户事件之后自动 线。这不是后台线程的情况——当方法是 调用取决于平台和发布版本,所以你 不应依赖特定的时间。如果次要上下文不是 在主线程上,您应该自己调用 processPendingChanges 合适的时机。

【讨论】:

您确定这能解决上述问题吗?我不认为 N​​SFetchedResults 控制器正在监听来自 background 上下文的更改通知。 mergeChangesFromContextDidSaveNotification: 执行(几乎)与processPendingChanges 相同的过程,并发布相应的通知。 这不是mergeChangesFromContextDidSaveNotification 执行与processPendingChanges 相同的过程,而是processPendingChanges 作为合并的一部分被调用。 processPendingChanges 保证在每个运行循环结束时(至少在 macOS 上)或每次保存上下文时被调用。它也被称为合并的一部分。

以上是关于带有谓词的 NSFetchedResultsController 忽略从不同 NSManagedObjectContext 合并的更改的主要内容,如果未能解决你的问题,请参考以下文章

带有基于依赖属性的谓词的 NSFetchedResultsController

带有 groupBy 的 nspredicate 不喜欢带有 nsdate 的谓词比较

带有函数参数的 CoreData 谓词

带有谓词的 NSFetchedResultsController 忽略从不同 NSManagedObjectContext 合并的更改

带有谓词的弹簧数据 JPA 方法 findAll() - QueryDslPredicateExecutor

包含带有谓词的属性时的异常