Suppose i want to observe a property named 'isEnabled
' on a property named 'controller' on self. AFAIK i have two options for installing such kind of observation:
1. [self.controller addObserver:self forKeyPath:@"isEnabled" options:0 context:nil];
2. [self addObserver:self forKeyPath:@"controller.isEnabled" options:0 context:nil];
I noticed the practical difference between the two approaches - on the second approach i will get a notification if the 'controller' object on self was replaced while with the first approach I will be notified only when 'isEnabled
' property is changed on the same instance on which I installed the observation.
My question is where the hell is this documented if at all? I know it works but should I use it?
I could not find any mention of such behavior in Apple docs, though some other dudes mentioned it in forums. Any reference will be gladly accepted.
Thanks.
It's not just that you'll get a change notification if the controller
property changes, it's that KVO will switch to tracking the isEnabled
property of the new controller and stop tracking the isEnabled
property of the old controller.
This is implicit in the notion of a key path. Key-Value Observing is built on top of Key-Value Coding. The Key-Value Coding Programming Guide says this about key paths in Key-Value Coding Fundamentals:
A key path is a string of dot separated keys that is used to specify a sequence of object properties to traverse. The property of the first key in the sequence is relative to the receiver, and each subsequent key is evaluated relative to the value of the previous property.
For example, the key path
address.street
would get the value of theaddress
property from the receiving object, and then determine thestreet
property relative to theaddress
object.
The meaning of -addObserver:forKeyPath:options:context:
is not "follow the key path to the final element and observe that property on the second-to-last object". It's "observe this key path of the receiver object". The key path is always considered starting from the receiver.
Put another way, for your second code example, it's not "observe the isEnabled
property of the controller
of self
" (that's the meaning of your first example). The meaning is "observe the controller.isEnabled
of self
. Any time that the result of evaluating the expression [self valueForKeyPath:@"controller.isEnabled"]
has or might have changed, notify me."
I know it works but should I use it?
Yes, you should use it. It's the intended meaning of the API. It's why the method describes its parameter as a key path rather than just a key.