2012-02-10 66 views
37

当使用addObserver:forKeyPath:options:context:观察对象上的值时,最终您需要在该对象上调用removeObserver:forKeyPath:以稍后进行清理。但在此之前,是否可以检查一个对象是否真的在观察该属性?KVO - 如何检查对象是否是观察者?

我试图确保在我的代码中,一个对象只在需要时才会被删除,但有些情况下观察者可能会尝试删除自己两次。我正在努力防止这种情况发生,但为防万一,我一直在试图弄清楚是否有办法检查我的代码是否实际上是某个事物的观察者。在NSKeyValueObserving协议

+0

KVO,因为它有一个相当粗糙的API。有些库可以简化它的使用,甚至允许你为了方便而使用块。详情请查阅http://thirdcog.eu/pwcblocks/#goodies。我也有我自己的实现能够自动删除观察员,当任何对象被释放。它尚未在实际应用中进行过测试,但您可能还是要仔细看看。在GitHub上搜索'tastykvo'。 – 2012-02-10 17:46:33

回答

43

[...]是否有可能检查一个对象是否实际上正在观察该属性 属性?

号当志愿打交道,你应该始终牢记以下模型:

当建立一个观察你是负责清除,准确的观察。观察是通过它的上下文来确定的 - 因此,上下文必须是独特的。当接收到通知时(并且在Lion中,当移除观察者时),您应该始终测试上下文,而不是路径。

处理观察对象是,以去除,并在观察对象的二传手建立观测的最佳实践:

static int fooObservanceContext; 

- (void)setFoo:(Foo *)foo 
{ 
    [_foo removeObserver:self forKeyPath:@"bar" context:&fooObservanceContext]; 

    _foo = foo; // or whatever ownership handling is needed. 

    [foo addObserver:self forKeyPath:@"bar" options:0 context:&fooObservanceContext]; 
} 

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context 
{ 
    if (context == &fooObservanceContext) { 
     // handle change 
    } else { 
     // not my observer callback 
     [super observeValueForKeyPath:keyPath ofObject:object change:change context:context]; 
    } 
} 

- (void)dealloc 
{ 
    self.foo = nil; // removes observer 
} 

当使用志愿,你必须确保这两个对象,观察者和observee,只要观察到位,他们就活着。

当添加一个观察,你必须平衡这与一个删除相同的观察。不要假设,你是唯一使用KVO的人。框架类可能会将KVO用于自己的目的,因此请始终检查回调中的上下文。

我想指出的最后一个问题:观察到的属性必须符合KVO。 You can't just observe anything

+0

您是否需要将fooObservanceContext设置为任何内容,或者在添加观察者时需要注意? – jrturton 2012-02-10 17:59:58

+2

它会自动初始化为零,但在这种情况下,它仅用于其地址。我们需要一个独特的'context'值。由于我们不知道其他人用作上下文的情况,因此这似乎是创建以前不太可能使用的值的一种很好的方式。 – 2012-02-10 18:04:08

+0

好的,所以它有一个地址,因为它是静态的,这就是你使用&?传递的东西。我对事物的所有方面都不太热衷,感谢解释! – jrturton 2012-02-10 18:06:03

25

部分是这样的:

- (void *)observationInfo 

应列出观察员。

编辑 仅用于调试。

+1

我只是写了一个答案,该列表显式不可用,因为'observationInfo'被记录为返回一个不透明的指针(实际上,它可能是也可能不是一个对象)。这听起来准确吗? – Tommy 2012-02-10 17:34:56

+0

@Tommy最有可能的是准确的。我只是在文档中写道:“返回一个标识所有观察者信息的指针”。我怀疑你比我更了解这一点。 – Rayfleck 2012-02-10 17:42:12

+3

你不能在生产代码中使用它,但在调试器中它非常有用:键入'po [observedObject observationInfo]',你可以很好地了解观察者和关键路径。 – 2012-02-10 17:43:47