4

像这样实现 KVO 是否安全:

[self addObserver:self
       forKeyPath:@"restaurant.oldestOrder.patron.frustrationLevel"
          options:0 context:nil];

......当你知道它oldestOrder可能会改变或变为 nil,而以前的oldestOrders可能会被释放?

4

1 回答 1

6

执行摘要:

您永远不需要为同一个键添加两次观察者,因为中间的键发生了变化,NSKeyValueObserving这会为您完成。

只要您的-oldestOrder方法不返回悬空指针,就不会中断。


KVO 的工作方式是,当您将自己添加为观察者时,观察者会以对象的形式添加到被观察对象的列表中NSObservationInfo。简单的。一个NSObservationInfo对象只是一个原始键(不是路径)、一个要监视的对象、一个要调用的观察者、一个指向您传递的上下文的指针,以及其他一些簿记工作。

当您观察键的路径时,通过各个NSObservationInfo对象观察观察者关系,这些对象保存在被调用对象的列表中,就好像整个路径是您调用的对象的属性一样-addObserver

在您的示例中self观察restaurant,但是该addObserver:方法随后NSObservationInfo在后台创建对象,这些对象被添加为沿路径的每个对象的观察者,并且这些对象也被添加到您自己的观察者列表中。

当你观察@"A.B.C.D"一个对象时,它会创建四个NSObservationInfo对象,每个键关系一个,这些对象作为观察者添加到路径上的每个键,所以你得到一个NSObservationInfo对象监视A被调用,一个监视,B一个A监视CB等等。当这些 NSObservationInfo 对象之一观察到更改时,它会将其作为对整个keypath-addObserver的更改传递给原始调用者。

(这是一个实现细节,但它应该有助于解释。)

当路径中间的对象被 nil'd 或删除时,-willChangeValueForKey注意到这一点并尽职尽责地删除NSObservationInfo对象作为观察者,沿着 nil'd 对象之后的路径。但是这些NSObservationInfo对象仍然存在,并且它们仍然知道他们想要查看的键,并且当-didChangeValueForKey被调用时,它会查看键的新值,如果它的键名与它的NSObservationInfo对象链正在寻找的键名匹配,它会将他们附加为新的观察者。

因此,当路径上的任何元素@"restaurant.oldestOrder.patron.frustrationLevel"发生更改时,您将收到更改通知,但NSKeyValueObserving机器将尝试在更改后与该路径末尾的键重新建立关系,以及任何后续更改。

这是Cocoatron 对 this 的实现,你可以自己看看它是如何工作的。

于 2013-05-14T01:05:02.907 回答