开发者

Manual Cocoa Binding not changing Observed KeyPath

开发者 https://www.devze.com 2023-03-18 08:57 出处:网络
I\'m changing a cocoa binding programatically. I\'m binding a NSTextField\'s value to the selection of an ArrayController.After I manually change the binding, I\'m getting the \"not key-value coding c

I'm changing a cocoa binding programatically. I'm binding a NSTextField's value to the selection of an ArrayController. After I manually change the binding, I'm getting the "not key-value coding compliant for the key.." error, with the key being the old key, not the new one.

Check out the code:

NSTextField *textField = [self listTextField];   

NSDictionary *currentBindInfo = [textFieldTableViewCell infoForBinding:NSValueBinding];
NSLog(@"pre-change bindings for textField: %@", 开发者_Go百科currentBindInfo);

/* Change the binding.  [Tried unbind: first, no difference] */
[textField bind:NSValueBinding
                      toObject:[currentBindInfo valueForKey:NSObservedObjectKey] 
                   withKeyPath:@"objectValue.iLifeProductName"
                       options:[currentBindInfo valueForKey:NSOptionsKey]];

/* Log the info so we can confirm it changed. debugging. */
NSLog(@"post-change bindings for textField: %@", [textFieldTableViewCell infoForBinding:NSValueBinding]);

To troubleshoot, I call 'infoForBinding' before and after the change and it looks to be changed correctly. I can see the old value, then I call bind:toObject... and dump the infoForBinding a second time, and the value has changed for the binding:

2011-07-06 22:36:23.137 My App 2011[14640:407] pre-change bindings for listTextFieldTableViewCell: {
NSObservedKeyPath = "selection.osxProductName";
NSObservedObject = "...sameTextField... 0x4009cc380>";
NSOptions =     {...same... };
}

2011-07-06 22:36:23.138 My App 2011[14640:407] post-change bindings for listTextFieldTableViewCell: {
NSObservedKeyPath = "selection.iLifeProductName";
NSObservedObject = "...sameTextField... 0x4009cc380>";
NSOptions =     {...same... };
}

But the code is still calling the original key:

2011-07-06 22:36:23.231 My App 2011[14640:407] [ valueForUndefinedKey:]: the entity ILifeVersion is not key value coding-compliant for the key "osxProductName".

--

The NSArrayController is bound to a ManagedObjectContext, the entity name is being changed earlier with this:

  [[self listAC] setEntityName:entityName];

Is the original keyValuePath being cached somewhere that I need to clear out? Is there a message like willChange/didChangeValueForKeyValuePath that I need to send to the binding or arrayController when I change the observed keypath?

Ideas?

Thanks!


As @noa pointed out, you’re looking at the binding on the cell, but changing the binding on its control. That’s bound (ahem) to cause problems.

Replace this:

[textField bind:NSValueBinding
                  toObject:[currentBindInfo valueForKey:NSObservedObjectKey] 
               withKeyPath:@"objectValue.iLifeProductName"
                   options:[currentBindInfo valueForKey:NSOptionsKey]];

with this:

[textFieldTableViewCell bind:NSValueBinding
                  toObject:[currentBindInfo valueForKey:NSObservedObjectKey] 
               withKeyPath:@"objectValue.iLifeProductName"
                   options:[currentBindInfo valueForKey:NSOptionsKey]];

And see if it works better.


The explanation for this is a bit arcane, and I’m doing it from memory, so please excuse me if I get some of the details wrong.

Because NSControls and their NSCell works so closely together, you can actually bind to either the control or the cell in most instances, and you’ll get very similar results. That is, there’s code in the control to call the proper methods on its NSCell if the control’s been bound to, and vice-versa.

This means that if, in XIB, you bind to one or the other things will work, which is good. It also means you can bind to a cell in cases where you have multiple cells per view, so that’s good. HOWEVER, it can lead to confusion, because in fact you can actually bind to both your view and its cell, and in fact bind them in different ways, and then they’ll crosstalk.

In your example, I believe you’re adding a second binding to the NSControl in addition to the one on its NSCell. You’re doubly-bound. That’s no good.

In terms of best practice, I try to bind only to NSControls unless I have a good reason to drop down to NSCells. Partly because it matches what I do in XIB, partly because any standard helps reduce exactly this problem, and partly because NSCells are being gently deprecated.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号