I have read the following thread: http://www.cocoabuilder.com/archive/message/cocoa/2008/6/27/211362 (the useful part of it) and mostly figured out the matter myself and coped to make my code work. I will now briefly set forth my understanding and appreciate if some more experienced colleague proved me right or wrong.
Conceptually, binding is an informal protocol (NSKeyValueBindingCreation) that objects can implement to establish one- or two-way connection between each other. The protocol itself does not imply whether the connection is one-way or two-way. There is a basic implementation of NSKeyValueBindingCreation in NSObject that provides one-way connection between two objects, where an object specified in the initial bind:toObject: message becomes the observed object, and the object that receives the bind: message becomes the observer. This default implementation can be re-used for implementing (at least) simple bindings (the one-way part of it). In fact, the simple one-way binding implemented in NSObject can be (roughly) thought of as a thin-layer addition over the KVO mechanism, i.e. the bind: message is kind of a way of sending addObserver: message in reverse direction from the observer to the observed. Also, bindings have names. This is the most confusing part for newbies. An object may expose a set of bindings, which are not equivalent to that object's properties, even though they may (or rather should not) have identical names. It is why bindings of Cocoa objects are documented separately from its properties and messages, here: http://developer.apple.com/documentation/Cocoa/Reference/CocoaBindingsRef/CocoaBindingsRef.html The binding names can be thought of as string keys to an internally maintained dictionary of connections. Although it is physically possible to bind to object property names instead of binding names, it is a mistake. (These binding names can also be exposed in IB by sending the +exposeBinding message in +initialize etc. and implementing an IB palette. Unless you implement the palette, there is unfortunately no way to make the bindings appear in IB. Luckily, there is no need to necessarily expose the bindings "formally", they will work by default. You just need to establish them manually by sending the bind: message. In a document-based application, this is done in the windowControllerDidLoadNib message.) In order to make use of the NSObject's default implementation of binding, you need to have a getter and setter messages with the same name as the binding name, inside the receiver of the bind: message, otherwise you will get the "class is not KVC/KVO-compliant" error. Note that these accessor methods should not necessarily be declared in the interface, because they are called via KVC. -(id)someBinding { return m_someBinding; } -(void)setSomeBinding:(id)value { m_someBinding = value; // do what you need // but don't fire the binding back } In order to make a binding bi-directional, the receiver of the bind: message needs to implement some custom logic that queries the bindings established on self and if they are available, sends the corresponding message on it. Like this: - (void)fireSomeBinding:(id)someValue { NSDictionary* bindingInfo = [self infoForBinding:SOME_BINDING_NAME]; if (bindingInfo != nil) { id target = [bindingInfo valueForKey:NSObservedObjectKey]; NSString* keyPath = [bindingInfo valueForKey:NSObservedKeyPathKey]; // ignore options [target setValue:someValue forKeyPath:keyPath]; } } Note that this message should be only invoked from a message that originates from an external source, such as a view, or user mouse/keyboard event, but not incoming from the same binding's setter message. Otherwise, you can end up with firing back the binding that has just reported a change in the observed value. Finally, many Cocoa widgets and controllers already implement bi-directional bindings, so you only need to implement the above code if you want to expose some bindings in a custom view or another kind of custom object that implements some non-trivial connection to a view. For example, I needed to use the above technique in a custom toolbar "controller" (the MyController), because I wanted it to observe the value of the MyDocument's currMode property and select the corresponding button on the toolbar. The answers to my other questions are: > 1) Should I send the bind message to myDocument to observe > myController as well? I used to think that bindings are two-way > inherently, i.e. the object whose "bind" message is invoked, stores > its observed object and when the observer's property changes, it > updates the observed object automatically. Am I wrong? No I should not. > 2) Am I allowed to send [myController setCurrMode:] in order for the > binding to fire, or am I obliged to always send [myController > setValue:... forKey:@"currMode"] for this? It does not matter. Both work. On Tue, Sep 2, 2008 at 8:25 AM, Oleg Krupnov <[EMAIL PROTECTED]> wrote: > I have two objects: a MyDocument (NSDocument subclass) and a custom > MyController controller (NSObject subclass). In the MyDocument there > is "currMode" property. The controller class also has the currMode > property. I want these two properties to be bound to each other > two-way, so that when either of the properties changes, the other > updates respectively. > > What I do: > From within MyDocument's windowControllerDidLoadNib message: > > [myController bind: @"currMode" toObject: self withKeyPath:@"currMode" > options:nil]; > > I do not override bind, unbind etc. of MyController relying on the > default implementation of bindings in NSObject. > > Now when the myController's currMode properties changes by its view, > nothing happens in MyDocument. It's setCurrMode is not sent. > > What am I doing wrong? > > I have two accompanying questions: > 1) Should I send the bind message to myDocument to observe > myController as well? I used to think that bindings are two-way > inherently, i.e. the object whose "bind" message is invoked, stores > its observed object and when the observer's property changes, it > updates the observed object automatically. Am I wrong? > > 2) Am I allowed to send [myController setCurrMode:] in order for the > binding to fire, or am I obliged to always send [myController > setValue:... forKey:@"currMode"] for this? > _______________________________________________ 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 [EMAIL PROTECTED]