带有谓词的 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
中保存、合并更改。但是NSFetchedResultsController
的fetchedObjects
不会改变。控制器也不会在委托上调用-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 合适的时机。
【讨论】:
您确定这能解决上述问题吗?我不认为 NSFetchedResults 控制器正在监听来自 background 上下文的更改通知。mergeChangesFromContextDidSaveNotification:
执行(几乎)与processPendingChanges
相同的过程,并发布相应的通知。
这不是mergeChangesFromContextDidSaveNotification
执行与processPendingChanges
相同的过程,而是processPendingChanges
作为合并的一部分被调用。 processPendingChanges
保证在每个运行循环结束时(至少在 macOS 上)或每次保存上下文时被调用。它也被称为合并的一部分。以上是关于带有谓词的 NSFetchedResultsController 忽略从不同 NSManagedObjectContext 合并的更改的主要内容,如果未能解决你的问题,请参考以下文章
带有基于依赖属性的谓词的 NSFetchedResultsController
带有 groupBy 的 nspredicate 不喜欢带有 nsdate 的谓词比较
带有谓词的 NSFetchedResultsController 忽略从不同 NSManagedObjectContext 合并的更改