I found the solution, and it's all my fault.

The object 'foo' was meant to be a singleton instance of class 'Foo'.  I always 
access it through [foo instance], which enforces that.  After 'foo' is created, 
the nib is loaded in which the binding was expressed.  In the process (see 
stack below**), -[Foo init] is called.  My override of -[Foo init] didn't have 
singleton smarts, so I happily handed a different m_contents to the controller.

So I thought that bindings had duplicated the result of -(id)[foo contents], 
but actually, I had two different 'foo's.

Truly a foo-lish mistake.

** le stack
    -[Foo init] 
    -[NSCustomObject nibInstantiate]
    -[NSIBObjectData instantiateObject:]
    -[NSIBObjectData nibInstantiateWithOwner:topLevelObjects:]
    loadNib


On Dec 13, 2011, at 12:11 PM, Eric Slosser wrote:

> Thanks for the pointers, Quincy.  However, I implemented the following 
> accessors, checked I wasn't directly touching m_contents except in my init, 
> and the problem persists.
> 
>    - (void) setContents:(id)newValue
>    - (NSUInteger)countOfContents
>    - (id)objectInContentsAtIndex:(NSUInteger)idx
>    - (void)insertObject:(id)obj inContentsAtIndex:(NSUInteger)idx
>    - (void)removeObjectFromContentsAtIndex:(NSUInteger)idx
> 
> I implemented -(BOOL)[Foo respondsToSelector:] to see what else I might be 
> missing, but Foo is only asked about '_finishedMakingConnections'  and 
> '_autounbinder'.  If I'm still missing an accessor, it must be determined 
> without using respondsToSelector:.
> 
> On Dec 8, 2011, at 12:34 AM, Quincey Morris wrote:
> 
>> 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/eric.slosser%40v-fx.com
> 
> This email sent to eric.slos...@v-fx.com
> 
> 

_______________________________________________

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