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

Jos*_*ler 39 objective-c key-value-observing ios

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

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

Nik*_*uhe 44

[...]是否有可能检查某个物体是否真的在观察该物业?

不.在处理KVO时,您应始终牢记以下模型:

建立观察时,您有责任删除该确切的观察结果.观察是通过其背景来确定的 - 因此,背景必须是独特的.当接收通知时(在Lion中,当移除观察者时),您应该始终测试上下文,而不是路径.

处理观察对象的最佳实践是,在观察对象的setter中移除和建立观察:

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
}
Run Code Online (Sandbox Code Playgroud)

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

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

最后一个问题我想指出:观察到的属性必须符合KVO标准.你不能只观察任何东西.

  • 它会自动初始化为零,但在这种情况下,它仅用于其地址.我们需要`context`的唯一值.由于我们不知道其他人使用什么作为上下文,这似乎是创建一个以前不太可能使用的值的好方法. (2认同)
  • @SpacyRicochet不要将对象指针`[NSNumber numberWithBool:YES]`用作KVO上下文.它不是唯一的(经常使用的NSNumbers被重用).但是,使用实例变量的地址是安全的. (2认同)

Ray*_*eck 26

NSKeyValueObserving协议的一部分是这样的:

 - (void *)observationInfo
Run Code Online (Sandbox Code Playgroud)

应列出观察员.

编辑 仅用于调试.

  • 你不能在生产代码中使用它,但是在调试器中它非常有用:输入`po [observedObject observationInfo]`你可以很好地概述观察者和关键路径. (3认同)