合并更改后的KVO通知

10
我正在使用KVO观察NSManagedObject的更改。我观察的NSManagedObject是位于主队列上的NSManagedObject上下文的一部分。
当我在后台(私有队列并发类型)上更新此对象,然后将保存的更改合并到我的主队列上下文中(在mergeChangesFromContextDidSaveNotification中),KVO通知按预期触发。
但是,我期望通知仅对实际更改的关键路径触发,而是NSManagedObject的所有关键路径。即使它们没有更改,我也会收到对象每个关键路径的KVO通知。 这是设计缺陷还是我的问题? 在苹果文档中看不到任何内容...

你如何处理通知?你应该查看通知userInfo字典的NSUpdatedObjectsKey。 - random
我实现了这个方法:- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context; - aloo
现在我可以查看更改字典并查看旧值,以确定其是否已从当前值更改 - 但是,如果NSManagedObject甚至没有为给定的键路径更改,为什么我首先会收到KVO通知呢? - aloo
你应该监听NSManagedObjectContextObjectsDidChangeNotification而不是mergeChangesFromContextDidSaveNotification吗?也许当它合并时,它会将合并视为“技术上”的更改? - random
我不会监听它们。那些是CoreData通知。我使用KVO直接观察NSManagedObject上的更改。导致所有这些KVO通知触发的更改是合并到UI上下文中的结果。 - aloo
哦,我明白了。那我得再做些研究 :P 虽然这是个难题,但还是给你点赞。 - random
2个回答

3
在OS X和iOS上观察到的但未记录的行为是,保存会计入整个NSManagedObject的更改而不仅仅是不同元素。您可以在此网站、openradar.appspot.com等地方找到关于绑定等各种后果的抱怨。这个问题似乎也会出现明显的KVO触发。最简单的处理方法(在“只需在保存时重新显示所有内容”之后最简单的方法,我认为这是一个很好的第一步选择,直到有人抱怨)是监听通用的保存通知,然后在每个更新的对象上调用-changedValues来挑选您感兴趣的特定更新对象。如果这对您的用例来说效率过低,您可以为您的属性制作自定义访问器(mogenerator在这方面非常有帮助),以收集对您感兴趣的所有属性的更改标志;并在保存后将其分派为通知。
假设我们有一个专业的体育团队应用程序(链接),它会不断地更新后台解析的JSON源。各种团队、球员、比赛等NSManagedObjects的所有影响显示的属性都有自定义访问器,这些访问器会设置一组标志(playerStatsChanged、teamStatsChanged、leagueRankingsChanged、yadayadayadaChanged),对应于应用程序中哪些页面需要在当前获取和解析线程完成后重新显示。然后,一旦保存完成,它会触发一个通用的“更新这些屏幕”的通知,并带有该标志设置结构。你可能已经将单个更改路径通知合并到某些更高级别的“更新此屏幕”类型逻辑中了,对吧?嗯,在属性设置器级别上,这基本上是您可以在大多数合理的用例中做到的最低开销点。当然,在我们这里的体育团队应用程序等任何重复获取更新设计中,都是如此。

感谢您的出色回复。有没有任何链接可以证明这是几个人都知道的问题?只是想确保我没有做错什么。我将沿着检查KVO通知的路径前进,看看旧值是否与新值不同 - 如果是,则更新UI。 - aloo
例如,查看此开放式雷达错误--http://openradar.appspot.com/6624874--您在保存到对象上使用KVO实际上等同于他的解决方案3。 - Alex Curylo
1
此外,关于KVO合规性的文档 -- http://developer.apple.com/library/mac/#documentation/cocoa/conceptual/KeyValueObserving/Articles/KVOCompliance.html -- 指出,除非编写特定代码检查更改,否则在每个setValue上通知是默认的。Core Data团队是否为每种可能的Core Data字段类型编写了该比较器,并在每次保存时调用每个对象的每个字段的适当比较器,以使保存到对象上的KVO按您所希望的方式工作?... 嗯,不是这样的。 - Alex Curylo

0

您可以通过手动通知来覆盖自动更改通知,仅针对您选择的键。请查看详细文档此处


我不想硬编码我想要通知的键。我希望仅在合并后实际更改的keypath上发送通知。目前,我收到了那些根本没有更改的keypath的通知。 - aloo

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接