On Dec 7, 2011, at 20:05 , Eric Slosser wrote:

> I have an NSTreeController whose 'content array' is bound to another object's 
> 'content' key.  
> 
> It appears that the binding mechanism duplicates the array that was returned 
> by [foo content].
> 
> This is bad, because changes that 'foo' makes later to its m_content never 
> show up in the window.  It's also bad because [NSTreeController 
> selectedObject] doesn't correspond to anything in the tree under [foo 
> content]. 
> 
> I can work around this by NOT using bindings to establish the controller's 
> content, instead using [NSTreeController setContent:].
> 
> 1. Where in the docs is this binding duplication described?
> 2. Is there a way to use bindings and avoid having [foo content] duplicated?

Based on this information, the problem is that your Foo class isn't KVO 
compliant for the "content" property.

Conceptually, it's a mistake to think of "content" as an array property (that 
is, as a property that has an array as its value). Conceptually, you should 
think of it as an indexed to-many relationship. 

The correct approach is to properly implement the KVC indexed collection 
accessors in your Foo class**. See:

        
http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/KeyValueCoding/Articles/AccessorConventions.html#//apple_ref/doc/uid/20002174-BAJEAIEE

Normally, you need to write only the 'insert' and 'remove' accessors. You can 
let all of the others default. Then, when changing the value of the property, 
you should never change m_content directly***. Instead, use the collection 
accessors, or use the mutable array proxy. For example, to add an object to the 
array, use either of these:

        [foo insertObject: newObject inContentAtIndex: newIndex]; // or …
        [[foo mutableArrayValueForKey: @"content"] insertObject: newObject 
atIndex];

Both of these are KVO compliant, and functionally equivalent.

Once you have this machinery set up, your binding to Foo's "content" should 
work properly.



** Of course, in practice, the Foo instance has to return *some* object that 
looks like an array as the value of the "content" getter, since properties have 
types. But think about what object ought to be returned. You don't want to 
return your 'm_content' array, because you're exposing an implementation detail 
to clients of your Foo class. You don't want to return a copy of your 
'm_content' array, because that of course won't change after being created.

Catch-22, isn't it? Ideally, the Foo instance would return [self 
immutableArrayValueForKey: @"content"] but unfortunately there's no such 
method. The simplest choice is probably to return the ivar, but to write no 
code that uses the @property value.

*** When using an array ivar to back an indexed collection property like this, 
it's safe to modify the ivar directly in the init method only (because there 
aren't any observers at this point). Apart from that method, you should always 
use the KVO compliant accessors.

_______________________________________________

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com

Reply via email to