NSTreeController has lousy KVO performance

It's time once again for me to try and justify my use of NSTreeController. Or more realistically, show how to work around its flaws.

The latest problem I hit was one of performance. In Sandvox we have a tree controller setup for the site outline. A whole bunch of controls from both the document window, and the Inspector are bound to its selection. e.g. @"selection.title"

This seemed to be working great, until we discovered a site with a blog containing a few hundred pages. Expanding the blog to show its contents in the site outline would beachball the app for several minutes. What was going on here?

Well, after some poking around in the debugger, it seems that when you observe a selection key path — e.g. by binding to it — NSTreeController implements that by observing the key path on every single content object. So exposing 100 new objects to the tree controller, means 100 new KVO observers added. And that's just for a single key path; Sandvox's Inspector observes dozens!

Hmm, what to do? Well, here's the solution I hit upon:

Give the Inspector its own array controller and bind all the controls to that. The array controller in turn is bound to @"selectedObjects" of the tree controller, with NSSelectsAllWhenSettingContentBindingOption.

The result is that the model objects are only being observed by the inspector controls when actually selected, as desired.

Update: Richard Somers points out to me that Apple has recommended this sort of approach at WWDC before. It’s covered in “Session 136 – Getting the Most Out of Cocoa Bindings” from WWDC 2005, which was available from Developer on iTunes when I grabbed it a few days ago, but now seems to have gone missing.

© Mike Abdullah 2007-2015