KVO issue with subclassing

by Tim Wood on September 24, 2008

Dave Dribin posted a nice article on Proper Key-Value Observer Usage that you should definitely check out. Something he mentioned in passing has been bugging me for a while:

You could check the object that’s passed in as well. Unfortunately, this doesn’t help the case where a subclass or superclass has registered a notification on the same key path of the same object.

If, however, you specify something unique for the context, you can use that to correctly identify your notifications.

Proper use of the KVO context will allow a single object to subscribe to a key across a parent and child class in some common cases, but there is a hidden danger.  If your two classes both follow the basic pattern of adding an observation when your object is created and removing it when your object is dying, all will be well.  But if you have a class that may toggle its observation on and off based on some varying criteria, you can get in trouble.

The core of the problem is an API flaw in KVO; -removeObserver:forKeyPath: doesn't include a context argument.  So, if you have an object that is subscribed to a key twice, with two different context pointers, there is no way to specify which one is to be removed.  If your object is dying and cleaning up all observations, this isn't a big deal.  But if your subclass logic wants to temporarily turn off its observation, it has no way to make sure that's what happens — it might instead end up removing the superclass observation.

Now, granted this is a relatively rare case that can be accounted for in your design.  But, this takes an otherwise general and extremely useful API and adds a bit of worry to it every time you use it.  You can't use it locally in a class without worrying about what your super- and subclasses are doing.

I've written up Radar 6244260 on this, including a test case.  Hopefully they'll add a proper -removeObserver:forKeyPath:context: and deprecate the current method for some future release.