可可 - -removeObserver:forKeyPath:和-removeObserver:forKeyPath:context:?之间的细微差别

时间:2013-05-29 02:21:39

标签: objective-c cocoa key-value-observing

短版:

-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: - 少删除方法存在。

基于我对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];
}

2 个答案:

答案 0 :(得分:0)

简短版本:-removeObserver:forKeyPath:context:仅在10.7中引入,因此都是。

长版:为什么你会有这个错误?在您的代码或系统中看起来像一个错误(我从未见过错误并且使用较短的版本)。这两种方法的描述并不表明应该有任何区别。如果没有其他人提出解释,并且您在代码中找不到任何内容,请向Apple报告错误。

答案 1 :(得分:0)

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

  

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

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

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