5
votes

I have a NSTextField bound to my model. If I change the content of the text field programmatically, the model isn't updated. I know that you're supposed to update the model instead.

But I'm trying to implement an NSTextField subclass that recognizes a scroll while the mouse is hovering over it to change it's numerical value. Obviously I don't have access to the model from this subclass. So you have any suggestions how I could do this?

SOLUTION (thanks to noa):

- (void)scrollWheel:(NSEvent *)theEvent {
    [self setFloatValue:[self floatValue] - [theEvent deltaY]];
    NSDictionary *bindingInfo = [self infoForBinding: NSValueBinding];
    NSObject *boundObject = [bindingInfo valueForKey:NSObservedObjectKey];
    NSString *keyPath = [bindingInfo valueForKey:NSObservedKeyPathKey];
    [boundObject setValue:[NSNumber numberWithFloat:[self floatValue]]
               forKeyPath:keyPath];
}
1

1 Answers

6
votes

You could either use target–action or Cocoa Bindings:

  1. Target–action: connect the text field's action selector to some updateValue action of the controller. Then, in the text field, invoke the selector after you change the text field's value. The action should fetch the text field's value and propagate it to the model.

  2. Cocoa Bindings: Set the text field's Value binding to a KVO-compliant property of a model object. Then you can update the cell's value and the binder will update the model object for you.

The advantage of these particular designs is that the coupling between the text field and the model property is handled either with the binding or the target. If you wanted to use a text field for a different property, you could just use a different action or a different binding, without modifying the custom text field code.

I'd probably use bindings, myself, which I consider to be less work, but target–action is perfectly fine too, and a little more straightforward.


Indeed, you did say "bound." I thought programmatic changes to the text field triggered an update, but since that's not the case, you can update the bound value yourself. Here's some code you can try:

NSDictionary *bindingInfo = [self infoForBinding:NSValueBinding];
[[bindingInfo valueForKey:NSObservedObjectKey] setValue:self.integerValue
                                             forKeyPath:[bindingInfo valueForKey:NSObservedKeyPathKey]];