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