Simple iOS Key Value Observing (KVO) Explained

There’s not as much on KVO when you google as there is on other forms of object-to-object communication.  I found a lot on Notification, for example.  But KVO is potentially much simpler.  I suspect that Notification is used more often because you can do a ‘chain of responsibility’ for an event as opposed to just assigning an observer.   However, just having an observer in a controller that can watch a particular property in another object and get notified of changes is a powerful and simple way to solve a whole class of problems.

I found that that the API has a few gotchas so I thought I’d jot this down to help others if possible.  The first thing you have to do is have an object with a property you want to observe.  Note that this must be a property and not merely an instance variable – and the variable must not be readonly.  Next, you must tell the object that it should report changes to that property.  You do this from where the object can be seen, not from within the object.  If you have an object ‘obj’ with a property ‘event’ you would do this:


[obj addObserver:self forKeyPath:@"event" options:NSKeyValueObservingOptionNew context:nil];

Here’s the gotcha though:  contrary to some of the examples you see in google searches, you cannot set options to 0.  It’s a bit mask without a useful default value, so you need to set it.  You probably want to know the new value of the property in the message, so you should set it to NSKeyValueObservingOptionNew.  If you set it to 0 it will just silently fail to send messages.

Next, in the object doing the observing you need to implement the NSKeyValueObserving Protocol.  Here’s a simple example:

 

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object
   change:(NSDictionary *)change
   context:(void *)context
{
    if ([keyPath isEqualToString:@"event"] )
    {
       // process here
    }
}

Now there’s one more gotcha:  when you change the value of the property in your object, you must use self to force the use of the setter.  For example, you must say:

self.event=NEW_VALUE;

and not just say:

event=NEW_VALUE;

The observer sub-system is tied into the getter and setter methods synthesized as the property.

I hope this helps someone!

[UPDATED]

There’s a great discussion on Hacker News about this – pointing out that I did not use the context pointer when I should have.  I learn yet more about this API.  You can follow the conversation here.

Comments are closed.