04 Oct 2008
Where The Magic Ends in Cocoa Bindings
Cocoa Bindings are awesome. Absolutely awesome. Apple has a great sample app called TwoManyControllers; it nicely demos the power of bindings, as there's practically no code at all. Using bindings correctly, I can wire up an interface ten times faster than with glue code. And then of course, there are the instances when I make a mistake. It doesn't work, and I don't know why. Anyone who's used bindings knows this frustration. However, the worst case scenario is when my mental model differs from the system model.
This is what happened when I decided to use NSBrowserCell in my source list (an NSOutlineView). I wanted a name and an icon for each entry in the list, and I had read NSBrowserCell was composed of exactly those. But when I tried to bind a column, I got the following error:
I iterated a lot on the problem. I even tried a variant where I passed in an array with the icon and the text, so I could get the objects through in a single bound value. No success. After exhausting every option, I finally started googling how other developers solved this problem. Luckily, someone else had encountered the same problem, and Ken Ferry (who works on the Cocoa Frameworks) explained the problem.
NSBrowserCell is a subclass of NSCell, not NSActionCell. NSActionCell lets you bind to the object's value, whereas NSCell does not. I hadn't considered that possibility. My mental model was inaccurate. You can check out what properties an object exposes to bindings by calling [self exposedBindings].
This is the output for NSBrowserCell.
And this is the output for NSActionCell.
NSActionCell exposes its "value" property, so the solution is to subclass NSActionCell.
Cocoa Bindings is an incredibly powerful tool. When I first started leveraging it, there was so little glue code that it felt like magic. I just didn't know where the magic ended. But understanding the machinery behind Cocoa Bindings just makes me appreciate it more. Especially when it "just works".