KVO - 如何检查对象是否是观察者?

时间:2012-02-10 17:15:57

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

使用addObserver:forKeyPath:options:context:观察对象上的值时,最终您需要在该对象上调用removeObserver:forKeyPath:以便稍后进行清理。在此之前,是否可以检查对象是否实际上正在观察该属性?

我已经尝试在我的代码中确保一个对象只在需要时删除了一个观察者,但在某些情况下,观察者可能会尝试将其自身移除两次。我正在努力防止这种情况,但为了以防万一,我一直试图弄清楚是否有办法首先检查我的代码是否真的是某个东西的观察者。

3 个答案:

答案 0 :(得分:44)

  

[...]是否可以检查对象是否实际观察到了这一点   属性?

没有。在处理KVO时,您应始终牢记以下模型:

建立观察时,您有责任删除该确切的观察结果。观察是通过其背景来确定的 - 因此,背景必须是独特的。当接收通知时(在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
}

使用KVO时,只要观察到位,就必须确保对象,观察者和观察者都活着。

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

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

答案 1 :(得分:26)

NSKeyValueObserving协议的一部分是:

 - (void *)observationInfo

应列出观察员。

修改  仅用于调试。

答案 2 :(得分:1)

我理解这是一个客观的问题。但是由于许多人一起使用Swift / objective-c,我想我指出了Swift4新API比旧版KVO的优势:

如果您多次对KVO执行addObserver,那么对于每次更改,您将获得observeValue的数量,相当于您将自己添加为观察者的当前次数。

  • 要摆脱自己,您必须拨打您添加的次数removeObserver
  • 将其删除超过所添加的数量会导致崩溃

Swift4 observe更聪明,更快捷!

  • 如果您多次执行,则不会在乎。每次更改都不会提供多个回调。
  • {{1}中只有一个invalidate就足够了。
  • token在开始观察者之前或您完成多次invalidat之前进行操作不会导致崩溃

因此,要专门回答您的问题,如果您使用新的Swift4 KVO,则无需在意。只需致电observe,您就可以了。但是,如果您使用的是较旧的API,请参阅Nikolai的答案