Take the 2-minute tour ×

I have several panels that contain NSTextField controls bound to properties within the File's Owner object. If the user edits a field and then presses Tab, to move to the next field, it works as expected. However if the user doesn't press Tab and just presses the OK button, the new value is not set in the File's Owner object.

In order to workaround this I have set Updates Continuously in the binding, but this must be expensive (EDIT: or at least it's inelegant).

Is there a way to force the bind update when the OK button is pressed rather than using Updates Continuously?

share|improve this question
What makes you think that "Updates Continuously" is expensive? Is it? Have you profiled? –  Rob Keniger Mar 31 '12 at 0:18
Well, no, as usual Rob, however it sets values in my core C++ library, which involves construction of std::string objects and conversion between NSString objects. It just seems inelegant and I thought there must be a better way. –  trojanfoe Mar 31 '12 at 7:59
I agree, it's just that making assumptions about performance is never a good idea. Premature optimisation is evil! –  Rob Keniger Mar 31 '12 at 23:19
Not true Rob. When you've been coding long enough, you get a feeling for what is right. The premature optimisation argument is rubbish - it's possible to code it efficiently first time round. It's important to be happy with your work and coding something with no consideration for performance just makes me unhappy. –  trojanfoe Apr 1 '12 at 8:37
I don't agree that the argument is rubbish, I have seen a lot of over-complicated, over-engineered code used to address perceived possible performance issues that don't exist in reality. However, I do agree that it's better to write code efficiently. In this case I think you're right to optimise it, it's more elegant, but from a performance point of view it probably won't make much of a difference to the end user. However, since we're rapidly veering off-topic I'll leave it at that. –  Rob Keniger Apr 1 '12 at 20:58
add comment

2 Answers

up vote 5 down vote accepted

You're right that you don't need to use the continuously updates value option.

If you're using bindings (which you are), then what you should be doing is calling the -commitEditing method of the NSController subclass that's managing the binding. You'd normally do this in your method that closes the sheet that you're displaying.

-commitEditing tells the controller to finish editing in the active control and commit the current edits to the bound object.

It's a good idea to call this whenever you are performing a persistence operation such as a save.

share|improve this answer
So does that mean you need a outlet to every control in the pane and need to call commitEditing on all of them before closing the pane? Or is there an easier way to implement this? –  trojanfoe Apr 1 '12 at 9:01
You don't call commitEditing on the controls, you call it on the NSController that the controls are bound to. This might be an NSArrayController, NSTreeController or just a plain NSObjectController. If you're binding your controls directly to a model object rather than via an NSObjectController, then you should change your bindings to use an NSObjectController as the intermediary object. The chief reason for this is that the NSObjectController will use the NSEditorRegistration protocol to tell controls to finish editing, whereas a plain binding will not. –  Rob Keniger Apr 1 '12 at 20:53
Hmmm, interesting. This is new to me and not mentioned at all in the book I used to initially learn Cocoa programming. I will look into this. Is there a problem with using my approach (as described in my answer) or is this considered a hack? –  trojanfoe Apr 1 '12 at 20:56
Unfortunately there's not a lot of good information about Cocoa Bindings out there, and no-one ever talks about NSEditorRegistration for some reason. Your solution is maybe a little hacky, because you're relying on the modification of the first responder to do the right thing, which, thankfully, it probably will. It would definitely be better (and certainly more elegant) to investigate the commitEditing method. –  Rob Keniger Apr 1 '12 at 21:03
As mentioned before the book I used to learn Cocoa programming was Aaron Hillegass's Cocoa Programming for Mac OS X - 4ed. Using the makeFirstResponder method was how he 'ends editing' and not commitEditing. I wonder why. Anyway I will leave it for now - I have a whole bunch of code to write to layout complex text objects in another custom view to worry about first. –  trojanfoe Apr 1 '12 at 21:06
add comment

The solution to this is to 'end editing' in the action method that gets called by the OK button. As the pane is a subclass of NSWindowController, the NSWindow is easily accessible, however in your code you might have to get the NSWindow via a control you have bound to the controller; for example NSWindow *window = [_someControl window].

Below is the implementation of my okPressed action method.

In summary I believe this is a better solution to setting Updated Continuously in the bound controls.

- (IBAction)okPressed:(id)sender
    NSWindow *window = [self window];
    BOOL editingEnded = [window makeFirstResponder:window];
    if (!editingEnded)
        logwrn(@"Unable to end editing");

    if (_delegateRespondsToEditComplete)
        [_delegate detailsEditComplete:&_mydetails];
share|improve this answer
add comment

Your Answer


