views:

74

answers:

2

Sorry for the clumsy title.

Imagine a simple UI to display the first names of a person's children...

As I initially only had one Person, I created an array controller and bound it to appDelegate.person1.children - this worked fine, as did binding a table column to display the first names.

However, I have since extended my program so that rather than a 'person1' there is an array or people maintained in the AppDelegate. I figured that I could simply keep the person1 attribute however, and use it to return the first item in the list:

- (Person *)person1{
    return [[self people] objectAtIndex:0];
}

I have confirmed everything is created correctly (during runtime), but I can't get the bound table column to display the first names of person1's kids.

Something to with KVO? How do I make sure that the table knows that when the persons array changes, person1 changes (and therefore the UI)?

Thanks

+1  A: 

@"How do I make sure that the table knows that when the persons array changes, person1 changes (and therefore the UI)?"

Wherever you change the children array make sure that you do it in between:

    - (void)willChangeValueForKey:(NSString *)key
    - (void)didChangeValueForKey:(NSString *)key

of the binded object.

Like:

[self willChangeValueForKey:@"children"];
[[self children] addObject: <some_new_child_object>]; // Add new child object to self.children
[self didChangeValueForKey:@"children"];
Raj
Thanks - this works well and is a very quick fix.
Ben Packard
@Ben PackardIt is a quick fix indeed, you should implement collection accessors as Peter suggested so that your code is extendable. If in future you need to bind to children of person2 / person3 etc, To-many Relationship will be useful.
Raj
+1  A: 

How do I make sure that the table knows that when the persons array changes, person1 changes (and therefore the UI)?

You mean the value of the person1 property is dependent on the value of the persons property. The former, then, is what's called a dependent key.

So, implement keyPathsForValuesAffectingPerson1 to return a set containing @"persons".

You also need to change the value of the property in an observable manner. Talking to the array directly won't cut it; nothing will know the value has changed. As Raj Pawan already noted, one way would be to explicitly send whole-value value-will/did-change notifications yourself.

The other way, which I find much easier to read and to write, is to implement array accessor methods for the array property (in your case, the persons property), and exclusively use these accessors to mutate the array (outside of init and dealloc). When you call your accessors, KVO notifications happen for free. This should include any dependent keys as well.

Peter Hosey
Thanks Peter - I'm trying this method next as it seems most correct and scalable.
Ben Packard