views:

610

answers:

3

I'm having trouble converting my Cocoa project from a manually-synched interface model to a bindings model so that I don't have to worry about interface glue code.

I followed the CocoaDevCentral Cocoa Bindings tutorial to make sure that I had covered all the bases, but things aren't working correctly. I have a master-detail interface, but I'm having trouble even getting the master portion of the interface to work correctly. No data is showing up in the master column, even though I've set up the bindings model similar to how it is shown in the tutorial. I've made sure all my controllers and objects have -(id)key and -(void)setKey:(id)key methods so that they're bindings-compliant, I've created a ControllerAlias object in my nib, connected it to my controller, created an NSArrayController that binds to one of the NSMutableArrays from the class that ControllerAlias connects to, made sure to set the type of objects that are contained within the array, and then I've bound a table column to the NSArrayController.

I'm getting no errors whatsoever in the Console, and setting NSBindingDebugLogLevel to 1 doesn't produce any errors either, that would help me figure out what the problem is.

The only other thing I could think of to make sure that things are working correctly is to check that the NSMutableArray that connects to the NSArrayController actually has something in it, and it does.

Any suggestions? What other typical pitfalls are there with Cocoa bindings that I should check?

+1  A: 

Have you put a breakpoint in your key: method to determine if it is getting called or not? If it isn't, then that would indicate that something isn't set up correctly for the binding in the table column (since you have verified that your array does have items in it).

I don't think that you need to create an Object Controller anymore (that tutorial is a bit out of date). Just create an Object in your NIB, and set its class to your Controller class. You can set up the bindings directly through it instead of the ObjectController.

To set up a binding, I do the following:

  1. Create an instance of my controller in the NIB.
  2. Create an NSArrayController, bind it to an array in my controller.
  3. For each column in the table, bind the value to a member of an object in the array controller.

That should be all that you need to do - I think they've cleaned this up quite a bit since bindings were first introduced a few versions ago.

Andy
A: 

I've created a ControllerAlias object in my nib,

What is a “controller alias”? Is this a model, controller, or view?

connected it to my controller,

What do you mean?

created an NSArrayController that binds to one of the NSMutableArrays from the class that ControllerAlias connects to,

Classes don't have NSMutableArrays.

What property of the array controller did you bind?

What object did you bind it to?

What key path of that object did you bind it to?

… and then I've bound a table column to the NSArrayController.

What property of the table column did you bind?

Which property (key path) of the array controller did you bind it to?

Peter Hosey
A: 

So in my original code, I was modifying the array (which the NSArrayController was representing) in awakeFromNib, not in init, so the changes weren't being reflected in the interface since I wasn't modifying the array via a key-value observing method.

I changed the code from

theArray = [[NSMutableArray alloc] init];
[theArray addObject:newThing];

to:

theArray = [[NSMutableArray alloc] init];
NSMutableArray *bindingsCompliantArray = [self mutableArrayValueForKey:@"things"];
[bindingsCompliantArray addObject:newThing];

I think the other solution is to do the loading in the -(id)init method instead of the -(void)awakeFromNib method, but that required a larger refactor, so I didn't do that.

I figured this out by adding a button to create a new thing in the array list via the NSArrayController, and when I clicked the button, a new thing was added to the array and my existing array magically showed up as well.

Another way (better, in my opinion) would be to add an `-addThingsObject:` accessor (assuming your property is named “things”). Then, your code in `-awakeFromNib` is `[self addThingsObject:newThing];`.
Peter Hosey
You should be able to keep your code in awakeFromNib if you add the objects directly to the NSArrayController instead of to the underlying array. This will cause the binding stuff to be notified of a new item, and update the UI appropriately.
Andy