3

精简版:

有什么用-removeObserver:forKeyPath:

为什么不总是使用-removeObserver:forKeyPath:context:

长版

在开发 Cocoa 程序时,我发现使用-removeObserver:forKeyPath:可能(但并非总是)会导致如下错误:

Cannot remove an observer <ObservedClass 0x1001301d0> for the key path "exampleKeyPath" from <__NSCFConstantString 0x100009138> because it is not registered as an observer.

而使用-removeObserver:forKeyPath:context:代替会工作得很好。

由于在设置观察时需要指定上下文(使用 -observeValueForKeyPath:ofObject:change:context:),我对为什么context:存在 -less 删除方法感到困惑。

根据我对NSKeyValueObserving Protocol的阅读,我认为删除可能适用于所有上下文中的指定观察者和指定键路径,但是-removeObserver:forKeyPath:(没有上下文)无法替代-removeObserver:forKeyPath:context:(上下文为NULL)似乎击落这个想法。

那么:为什么我会出现这个错误?上下文有什么作用-removeObserver:forKeyPath:?它与context:装备精良的弟弟有何不同?

代码示例

有问题的代码:

-(void) invalidate {
    [(id)observedObject removeObserver:self
                            forKeyPath:@"exampleKeyPath"];
}

非问题代码:

-(void) invalidate {
    [(id)observedObject removeObserver:self
                            forKeyPath:@"exampleKeyPath"
                            context:NULL];
}
4

2 回答 2

0

Short version: -removeObserver:forKeyPath:context: was only introduced in 10.7, hence both.

Long version: Why might you have the error? Looks like a bug, either in your code or the system (I've never seen the error and use the shorter version a lot). The descriptions of the two methods do not suggest there should be any difference. If nobody else comes up with an explanation, and you can't find anything in your code, then report a bug to Apple.

于 2013-05-29T03:07:27.433 回答
0

该文档对新方法的使用进行了很好的讨论:

检查上下文中的值,您可以准确确定使用哪个 addObserver:forKeyPath:options:context: 调用来创建观察关系。当同一个观察者多次注册同一个键路径,但使用不同的上下文指针时,应用程序可以明确地确定停止观察哪个对象

这只是一种更具体地确定要从对象中删除的绑定的方法。例如,我可能会绑定到一个键路径两次,但使用不同静态变量的内存位置,有点像dispatch_once()工作原理。上下文无关订阅方法是绑定到对象的唯一方法,直到 10.7 滚动并填补了这一空白。

至于您的 KVO 问题,问题可能出现在许多不同的情况下。最常见的情况是您订阅了一个线程,然后很快从另一个线程中删除了订阅。有时会发生这种情况,因为您尝试观察的对象即将解除分配,这意味着您将订阅一些恰好填充您需要的内存位置的虚假内存位置,然后从该垃圾指针中删除订阅是不可能的。无论哪种方式,请确保监视您正在使用绑定的方法,因为如果以错误的方式使用它们可能会有点不稳定。

于 2013-05-29T05:07:15.847 回答