Key value observing is quite a useful tool, no doubt about it. But it has a singularly annoying manner of informing the observer of a change. The -[NSObject observeValueForKeyPath:ofObject:change:context:] method is sent to the observer when a change occurs. It's up to the implementor to parse the `change' dictionary to figure out what changed.

When I use observers, I usually want a method called on my class when a change occurs, similar to target/action with UI elements. So my -[NSObject observeValueForKeyPath:ofObject:change:context:] is basically a set of if's for each key I'm observing that calls the appropriate method.

This turns out to be pretty nasty, especially when you have multiple classes in a hierarchy implementing the method. It wasn't obvious to me that I needed to call super in this method. Thirty minutes of debugging later, and I was convinced there had to be a better way of doing it.

To this effort, I present two new APIs. To NSObject, I add -[NSObject addObserver:forKeyPath:options:selector:] and to NSArray, -[NSArray addObserver:toObjectsAtIndexes:forKeyPath:options:selector]. The code is available here, or keep reading for the details.

Update 1.1: Two critical bug fixes. Please update to the new version if you have the old one. Also, anonymous svn is now available if you want to use an external. http://svn.shiftedbits.org/public/KVOAdditions/trunk.

NSObject:

@interface NSObject (KVOAdditions)

- (void)addObserver:(NSObject *)observer
         forKeyPath:(NSString *)keyPath
            options:(NSKeyValueObservingOptions)options
           selector:(SEL)aSelector;

@end

NSArray:

@interface NSArray (KVOAdditions)

- (void)addObserver:(NSObject *)observer
 toObjectsAtIndexes:(NSIndexSet *)indexes
         forKeyPath:(NSString *)keyPath
            options:(NSKeyValueObservingOptions)options
           selector:(SEL)aSelector;

@end

These allow you to observe a keyPath on an object and receive a message to the designated selector when the change occurs. Furthermore, the selector can have four different signatures that allow for different levels of information to be received. These selector formats are as follows:

/* Receive no information about the change */
- (void)valueDidChange;

/* Receive the raw change dictionary */
- (void)valueDidChange:(NSDictionary *)change;

/* If the observing options include either
 * NSKeyValueObservingOptionOld or NSKeyValueObservingOptionNew,
 * receive the old and new values */
- (void)valueDidChange:(id)old newValue:(id)new;

/* If the observing options include either
 * NSKeyValueObservingOptionOld or NSKeyValueObservingOptionNew,
 * receive the old and new values */
- (void)valueDidChange:(id)old newValue:(id)new prior:(BOOL)isPrior;

Feedback on these APIs, including suggestions and criticism (and even bugs!) are of course welcome.