Indeed

Things that seemed important enough at the time

Saturday, December 17, 2005

Using and Debugging Cocoa Bindings

I've got a couple of projects where I have been able to start using bindings recently, and I thought it would be worthwhile to document some of the things I've run across.

To start off with, make sure you read everything you can about bindings before you get in too deep. Since there isn't as much content out there as for other Cocoa topics (because it's pretty new), reading everything shouldn't be all that hard :)

Apple - KeyValueCoding
Apple - KeyValueObserving
Apple - Cocoa Bindings Reference

CocoaDev (searching for 'binding' - which has lots of related topics)
mmalc's page
Borkware - Quickies for Bindings

The easiest bindings to get started with are from the NSUserDefaultsController. I've been using them for quite a while, and they can be added to existing projects with very little change.

For VDLMidi I use an NSArrayController to populate the table. It's pretty close to the standard examples for tables that you can find on the web. After getting that working I wanted to add a search field, to mimic what you get from all of the CoreData examples (where dragging an entity into InterfaceBuilder hooks up a table and search UI for you). Most places on the web talk about doing this by subclassing NSArrayController - but there's a much easier way! You simply bind the search field's 'predicate' binding to the arrayController's 'filterPredicate' controller key (Note - I tried doing this the other way for quite a while - from the arrayController to the searchField - but I never got it to work). This only works on 10.4 and later, since the binding is new to Tiger. Since I wanted VDLMidi to work on Panther, I had to do more tricks to make it work - but that's a different post…

On another project last week I was trying to remove a bunch of UI updating code for an inspector. I setup things in the nib, but with lots of bindings and complex keypaths, there were quite a few things that weren't working. While I tried to figure them out, I searched through the headers to see if there was anything useful. The first thing I found was that it's still good to have an IBOutlet for your UI objects (and your NSControllers) so you can call various methods on them. Once you have your objects, here are some useful methods, starting from the top down:

NSKeyValueBinding -infoForBinding:
With a given UI object, this method will give you the keyPath and other information that is useful for working your way down to the model objects. I was spending most of my time with the @"value" binding, but you can use the '-exposedBindings' method to find what is available. I mainly used it as a sanity check on the values set in the nib, but then I would start tracking things down with the keyPath…

NSKeyValueCoding -valueForKeyPath:
You can call this method on your NSController to get to your model objects. When I bound a UI element to the keyPath "foo.bar", I would call down the chain to inspect each of the objects:

po controller
po [controller valueForKeyPath:@"foo"]
po [controller valueForKeyPath:@"foo.bar"];
etc.

I'm not entirely sure what's going on for some of this, but Cocoa seems to change some of the object classes for these to make KeyValueObserving work (that's my guess from the class name). Whatever they are doing seems to work though, so I've stopped worrying about it :)

NSKeyValueObserving -observationInfo
The method description makes it sound like this method and its companion setter are intended for greater things when overridden, but I haven't found a need for that. However, printing the result of this method gives an array that seems to list the observers for things that are bound to or through the object.



Between these and lots of time checking and rechecking my classes for KVC and KVO-compliance, I've fixed all of the problems I've found so far. Let me know if you know of other good techniques...

0 Comments:

Post a Comment

<< Home

 
Google