Search code examples
objective-ccocoabindingcocoa-bindingsnull

Binding returns default value (set with registerDefaults:) instead of zero


Here's my setup:

  • myTextField is bound to a key in the Shared User Defaults Controller. The user can only enter numbers in the text field.
  • Each time my application loads, I load default preferences (from the app's Resources folder) using [[NSUserDefaults standardUserDefaults] registerDefaults: ... ].
  • myMenuItem's title is bound to the same key in the Shared User Defaults Controller.

The issue:

When myTextField is empty, myMenuItem receives the default value that was loaded using registerDefaults: instead of some value that represents the empty field (I would expect 0 or nil).

For example, when the NSTextField is empty the menu item receives "2", the value that was loaded using registerDefaults:, instead of some value that means that the field is empty.

If I comment the registerDefaults: code, the binding returns nil as I would expect when there is nothing in the NSTextField.

I tried to mess around with many of the bindings' settings as well as experiment with placeholder values and I looked at the Cocoa Bindings and User Defaults docs but I could not find the solution.

Expected behavior:

  • When the text field is empty, I want myMenuItem to reflect that instead of using the default value that was registered using registerDefaults:.

Any help would be greatly appreciated.


Solution

  • I got some hints from the nice folks at irc.freenode.org #macdev and found the following to be the solution to my problem:

    Creating a subclass of NSFormatter (or NSNumberFormatter in my case) and overriding getObjectValue:forString:errorDescription: as follows overrides the default behaviour of returning nil (which makes the binding use the registered default value) to instead return 0 when the text field is empty.

    - (BOOL)getObjectValue:(id *)anObject forString:(NSString *)string errorDescription:(NSString **)error {
        if ([string isEqualToString:@""]) {
            *anObject = [NSNumber numberWithInt:0];
            return YES;
        } else {
            return [super getObjectValue:anObject forString:string errorDescription:error];
        }
    }
    

    A NSValueTransformer subclass' reverse conversion method would have also worked for this.