像这样实现 KVO 是否安全:
[self addObserver:self
forKeyPath:@"restaurant.oldestOrder.patron.frustrationLevel"
options:0 context:nil];
......当你知道它oldestOrder
可能会改变或变为 nil,而以前的oldestOrders
可能会被释放?
像这样实现 KVO 是否安全:
[self addObserver:self
forKeyPath:@"restaurant.oldestOrder.patron.frustrationLevel"
options:0 context:nil];
......当你知道它oldestOrder
可能会改变或变为 nil,而以前的oldestOrders
可能会被释放?
执行摘要:
您永远不需要为同一个键添加两次观察者,因为中间的键发生了变化,NSKeyValueObserving
这会为您完成。
只要您的-oldestOrder
方法不返回悬空指针,就不会中断。
KVO 的工作方式是,当您将自己添加为观察者时,观察者会以对象的形式添加到被观察对象的列表中NSObservationInfo
。简单的。一个NSObservationInfo
对象只是一个原始键(不是路径)、一个要监视的对象、一个要调用的观察者、一个指向您传递的上下文的指针,以及其他一些簿记工作。
当您观察键的路径时,通过各个NSObservationInfo
对象观察观察者关系,这些对象保存在被调用对象的列表中,就好像整个路径是您调用的对象的属性一样-addObserver
。
在您的示例中self
观察restaurant
,但是该addObserver:
方法随后NSObservationInfo
在后台创建对象,这些对象被添加为沿路径的每个对象的观察者,并且这些对象也被添加到您自己的观察者列表中。
当你观察@"A.B.C.D"
一个对象时,它会创建四个NSObservationInfo
对象,每个键关系一个,这些对象作为观察者添加到路径上的每个键,所以你得到一个NSObservationInfo
对象监视A
被调用,一个监视,B
一个A
监视C
,B
等等。当这些 NSObservationInfo 对象之一观察到更改时,它会将其作为对整个keypath-addObserver
的更改传递给原始调用者。
(这是一个实现细节,但它应该有助于解释。)
当路径中间的对象被 nil'd 或删除时,-willChangeValueForKey
注意到这一点并尽职尽责地删除NSObservationInfo
对象作为观察者,沿着 nil'd 对象之后的路径。但是这些NSObservationInfo
对象仍然存在,并且它们仍然知道他们想要查看的键,并且当-didChangeValueForKey
被调用时,它会查看键的新值,如果它的键名与它的NSObservationInfo
对象链正在寻找的键名匹配,它会将他们附加为新的观察者。
因此,当路径上的任何元素@"restaurant.oldestOrder.patron.frustrationLevel"
发生更改时,您将收到更改通知,但NSKeyValueObserving
机器将尝试在更改后与该路径末尾的键重新建立关系,以及任何后续更改。
这是Cocoatron 对 this 的实现,你可以自己看看它是如何工作的。