Search code examples
cocoabindingcocoa-bindingsnstextview

bind:toObject:withKeyPath:options: is one-way binding?


I have two windows: Window A is loaded from NIB; and Window B is created programmatically.

Both windows have a NStextView: the attributedString of the textview in Window A is bound to the the property text of a model using IB; while the attributedString of the textview in Window B is bound to text property of the model using -[NSObject bind:toObject:withKeyPath:options:] method.

[textview bind:@"attributedString"
      toObject:obj
   withKeyPath:@"text"
       options:nil];

Here is the weird thing: the textview in Window B is indeed bound to the obj.text, but the changes in the textview is never updated to obj.text. But, if I made changes in the textview of Window A, the obj.text and the textview in Window B are updated accordingly.

So I am thinking, the -[NSObject bind:toObject:withKeyPath:options:] method is only for one-way binding. I couldn't find a clear explanation in the Cocoa documentations. Does any one have experience with this problem? How do you implement two-way binding in code?


Solution

  • Cocoa bindings are inherently two-way, but certain behaviors (like continuous/live updating of text fields) require specific options to be set. In IB you will want to make sure that the "Continuously Updates Value" check box is checked. To get equivalent behavior programmatically, you will need to specify options on the binding. That might look something like this:

    [textview bind: NSAttributedStringBinding 
          toObject: obj 
       withKeyPath: @"text" 
           options: (@{ 
                     NSContinuouslyUpdatesValueBindingOption : @YES })];
    

    It's worth mentioning that when setting up a binding programmatically, it's worth checking an equivalent binding in IB and making sure you're passing all the same settings to the programmatic binding. For instance, I see in IB that the "Allow Editing Multiple Values Selection", "Conditionally Sets Editable", and "Raises For Not Applicable Keys" options are all checked by default for an NSTextView's Attributed String binding. That would mean our programmatic binding should probably really look like:

    [textview bind: NSAttributedStringBinding 
          toObject: obj 
       withKeyPath: @"text" 
           options: (@{ 
                     NSContinuouslyUpdatesValueBindingOption : @YES,
                     NSAllowsEditingMultipleValuesSelectionBindingOption : @YES,
                     NSConditionallySetsEditableBindingOption : @YES,
                     NSRaisesForNotApplicableKeysBindingOption : @YES })];