I've had a crack at implementing bindings for my own NSView subclass. It works, but there are problems with retain cycles when binding to File's Owner from a nib file. After reading into it a little, I discovered that Apple had the same problem a few years back but have fixed it with some magic undocumented class (NSAutounbinder).
There is a lengthy discussion of the retain cycle problem here http://www.cocoabuilder.com/archive/message/cocoa/2004/6/12/109600 . The workaround is to to unbind all bindings before the window controller is released, not before it is deallocated, in a place like windowWillClose:. This seems like an unnecessary hack to me.
My question is this: Is there any way to make custom bindings that work as well as the ones made by Apple, without using undocumented features? Am I going about this the wrong way?
UPDATE 2: I have found a solution that allows manually implemented bindings to work exactly like Apple's bindings. It takes advantage of the undocumented NSAutounbinder class, without actually using undocumented features. I will post the solution later today.
UPDATE: I've tried using exposeBinding:
, and it doesn't seem to make any difference. However, the NSObject
implementation of bind:toObject:withKeyPath:options:
half works. It propogates changes from bindee to binder (i.e. from model/controller to view), but doesn't work the opposite way. Also, although the bindee is obviously being observed, observeValueForKeyPath:ofObject:change:context:
is never triggered.
Example project here: http://www.tomdalling.com/wp-content/BindingsTest.zip
Apple's documentation indicates that you do, in fact, have to override bind:toObject:withKeyPath:options:
to implement manual bindings. See here: http://developer.apple.com/documentation/Cocoa/Conceptual/CocoaBindings/Concepts/HowDoBindingsWork.html
SIDE NOTE: I've investigated how the undocumented NSAutounbinder works, and here's what I know.
When a binding is created to an NSWindowController, the bound object is actually an NSAutounbinder that is acquired from the NSWindowController with -[NSWindowController _autounbinder]. NSAutounbinder is a non-retaining proxy for the NSWindowController object. It is non-retaining to avoid the retain cycle problem.
When -[NSWindowController release] is called and retainCount == 1, The NSAutounbinder unbinds all bindings to itself. This ensures that there are no dangling pointers to the object before it is deallocated.