bind:toObject:withKeyPath:options: Unidirectional or Bidirectional?
bind:toObject:withKeyPath:options: Unidirectional or Bidirectional?
- Subject: bind:toObject:withKeyPath:options: Unidirectional or Bidirectional?
- From: Jerry Krinock <email@hidden>
- Date: Fri, 29 Jan 2010 22:52:34 -0800
In "Cocoa Bindings Programming Topics" ▸ "What Are Cocoa Bindings" ▸ "Supporting Technologies", I read:
"A binding is established with a bind:toObject:withKeyPath:options:
message which tells the receiver to keep its specified attribute
synchronized ... with the value of the property... The receiver
must watch for ... changes in the object to which it is bound and
react to those changes. The receiver must also inform the object
of changes to the bound attribute. ... There are therefore two
aspects to keeping the model and views synchronized: responding
to user interaction with views, and responding to changes in
model values."
This clearly states, twice, that ind:toObject:withKeyPath:options: creates something which is bidirectional.
Then, in "Cocoa Bindings Programming Topics" ▸ "How Do Bindings Work" ▸ "BIndings in More Detail", I read:
"In its bind:toObject:withKeyPath:options: method an object must
as a minimum do the following:
• Determine which binding is being set
• Record what object it is being bound to using what keypath
and with what options
• Register as an observer of the keypath of the object to which
it is bound so that it receives notification of changes."
This tells me that, "as a minimum", a binding is only unidirectional.
How do you know when a binding is going to be unidirectional or bidirectional, and how can you control this? I've made a demo app which demonstrates both behaviors. It has a window with four checkboxes in it:
[ ] button1
[ ] button2
[ ] button3
[ ] button4
There are no bindings in the xib/nib. The four buttons are connected to four outlets in the app controller. In code, I created a Foo instance and a Bar instance, each with one BOOL property, respectively fooBool and barBool. Then I made the following bindings:
A. Bind button1's value to foo's fooBool
B. Bind button2's value to foo's fooBool
C. Bind button3's value to bar's barBool
D. Bind button4's value to bar's barBool
E. Bind bar's barBool to foo's barBool
Build and run the app.
First Experiment: Click/Checkmark button1
Result: The other three boxes all get checkmarks too.
Conclusion: Binding A worked in the reverse direction, then bindings B, E, C and D worked in the forward direction.
Second Experiment: Click/Checkmark button3
Result: Only the button4 gets checkmarked too.
Conclusion: Binding C worked in the reverse direction, Binding D worked in the forward direction, and binding E failed to work in the reverse direction.
Why are bindings A, B, C and D bidirectional but E is only unidirectional?
Jerry
Here's the code...
#import "BindMasterSlaveAppDelegate.h"
@interface Foo : NSObject {
BOOL m_fooBool ;
}
@property BOOL fooBool ;
@end
@implementation Foo
+ (void)initialize {
[super initialize] ;
// The following binding is not used. I just
// wanted to see if exposing it would make any
// difference. It does not.
[self exposeBinding:@"fooBool"] ;
}
@synthesize fooBool = m_fooBool ;
@end
@interface Bar : NSObject {
BOOL m_barBool ;
}
@property BOOL barBool ;
@end
@implementation Bar
+ (void)initialize {
[super initialize] ;
// Results are the same with or without the
// follining line.
[self exposeBinding:@"barBool"] ;
}
@synthesize barBool = m_barBool ;
@end
@implementation BindMasterSlaveAppDelegate
- (void)applicationDidFinishLaunching:(NSNotification *)aNote {
Foo* foo = [[Foo alloc] init] ;
Bar* bar = [[Bar alloc] init] ;
// The following four calls create bidirectional bindings (Why?)
[button1 bind:@"value"
toObject:foo
withKeyPath:@"fooBool"
options:0] ;
[button2 bind:@"value"
toObject:foo
withKeyPath:@"fooBool"
options:0] ;
[button3 bind:@"value"
toObject:bar
withKeyPath:@"barBool"
options:0] ;
[button4 bind:@"value"
toObject:bar
withKeyPath:@"barBool"
options:0] ;
// The following creates only a unidirectional binding (Why?)
[bar bind:@"barBool"
toObject:foo
withKeyPath:@"fooBool"
options:0] ;
// Another question. According to -bind:toObject:withKeyPath:options:
// documentation, bind: parameter is "The key path for a property
// of the receiver previously exposed using the exposeBinding: method."
// But it works fine even with +[Bar exposeBinding:] above commented
// out.
// Variation: If you #if 1 below, this "inverse" binding to make the above
// bidirectional. Now, checking button 3 or 4 will also propagate to
// all buttons too.
#if 0
[foo bind:@"fooBool"
toObject:bar
withKeyPath:@"barBool"
options:0] ;
#endif
}
@end
_______________________________________________
Cocoa-dev mailing list (email@hidden)
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:
This email sent to email@hidden