KVO问题“无法移除观察者”

时间:2010-07-28 15:19:22

标签: cocoa macos observer-pattern key-value-observing

我有一个NSArrayController链接到Core Data对象,设置为Auto Rearrange Content并按谓词过滤。一切顺利,直到我试图取消关系并指定另一个关系。此时,我的应用程序崩溃,我收到以下错误:

  

无法移除观察者    对于   关键路径“career.type”   来自Object,很有可能   因为关键“职业”的价值   没有适当的KVO就改变了   发送通知。检查   KVO遵守Person类。

从窥探中看来,将我的NSArrayController设置为Auto Rearrange Content会导致此问题。但我试图解决问题,而不必诉诸手动重新安排NSArrayController。这是触发错误的伪代码:

object.career = nil;
object.field = (Field *)item;

这是我的NSArrayController使用的谓词:

(career != NIL && career == %@) || (field != NIL && field == %@)

两个实例的%@是CoreData对象。

基本上,看起来好像NSArrayController具有为object.career.type设置的观察者,并且当自动删除该观察者时,使关系无效会导致问题。所以我想知道我是否会以错误的方式解决这个问题?我是否应该抓取对象的副本,将其从MOC中删除并将其重新插入,并将职业设置为nil并相应地设置字段?

如何正确通知观察者该类型已被取消?请注意,此处提到的所有属性和关系都使用符合vanilla KVO标准的getter / setter。

1 个答案:

答案 0 :(得分:4)

From apples documentation

错误和KVO通知

当Core Data将对象转换为故障时,会为对象的属性发送键值观​​察(KVO)更改通知(请参阅键值观察编程指南)。如果您正在观察变为故障的对象的属性并且随后实现了故障,则会收到其值实际上未更改的属性的更改通知。

虽然从您的角度来看,值没有在语义上发生变化,但内存中的文字字节随着对象的具体化而发生变化。键值观察机制要求Core Data在指针比较的角度考虑值时发出通知。 KVO需要这些通知来跟踪关键路径和相关对象的变化。


所以基本上你会得到一个通知,告诉你即使不是这样也会有变化。所以你必须检查对象是否已经成为一个错误。然后删除旧观察者并将新内容添加到同一路径...

对我来说这很有用(示例代码):

- (void) observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
    [super observeValueForKeyPath:keyPath ofObject:object change:change context:context];

    if ([keyPath isEqualToString:@"pageIndex"]) {

        // basically remove the observer from the fault object and assign the new
        if([object isFault]) {
            [object removeObserver:self forKeyPath:@"pageIndex"];
            [the_current_instance_returned_by_core_data addObserver:self forKeyPath:keyPath options:NSKeyValueObservingOptionOld context:NULL];
        } 

        // do whatever you want to do on change...

    }
}