binding NSTextField to NSNumber

后端 未结 4 857
醉话见心
醉话见心 2020-12-29 00:34

I\'m trying to use an NSTextField for integer user input. The text field is bound to an NSNumber property and in the setter method I cleanup the input value (make sure it\'s

相关标签:
4条回答
  • 2020-12-29 00:42

    There’s an important comment on Peter Hosey’s excellent answer that I’d like to bring up to the top level (because I missed it on my first pass).

    If you want to validate / modify the NSTextField each time a character is entered, rather than only when the user submits the field, then you can’t get what you want from bindings alone. You need to assign a delegate to the text field, and then implement - (void)controlTextDidChange:(NSNotification *)aNotification in the delegate. This will get called every time the text changes. If you want, you can call the value validator in controlTextDidChange.

    For example:

    - (void)controlTextDidChange:(NSNotification *)aNotification
    {
        NSError *outError;
        NSControl *textField = [aNotification object];
        NSString *myText = [textField stringValue];
    
        // myObject is the model object that owns the text in question
        // the validator can modify myText by reference
        [myObject validateValue:&myText error:&outError]];
    
        // update the NSNextField with the validated text
        [postingObject setStringValue:myText];
    }
    
    0 讨论(0)
  • 2020-12-29 00:54

    I think you need to set up a number formatter to your NSTextField.

    Go read up about formatters on Apple's website: Applying Formatters.

    0 讨论(0)
  • 2020-12-29 01:02

    I send the willChangeValueForKey: and didChangeValueForKey:, but the UI doesn't update to the new values while that text field is still active.

    There are very few reasons to send those messages. Usually, you can do the same job better and more cleanly by implementing and using accessors (or, better yet, properties). KVO will send the notifications for you when you do that.

    In your case, you want to either reject or filter bogus inputs (like “12abc”). The correct tool for this task is Key-Value Validation.

    To enable this, check the “Validates Immediately” box on the binding in IB, and implement a validation method.

    Filtering:

    - (BOOL) validateMyValue:(inout NSString **)newValue error:(out NSError **)outError {
        NSString *salvagedNumericPart;
        //Determine whether you can salvage a numeric part from the string; in your example, that would be “12”, chopping off the “abc”.
        *newValue = salvagedNumericPart; //@"12"
        return (salvagedNumericPart != nil);
    }
    

    Rejecting:

    - (BOOL) validateMyValue:(inout NSString **)newValue error:(out NSError **)outError {
        BOOL isEntirelyNumeric;
        //Determine whether the whole string (perhaps after stripping whitespace) is a number. If not, reject it outright.
        if (isEntirelyNumeric) {
            //The input was @"12", or it was @" 12 " or something and you stripped the whitespace from it, so *newValue is @"12".
            return YES;
        } else {
            if (outError) {
                *outError = [NSError errorWithDomain:NSCocoaErrorDomain code: NSKeyValueValidationError userInfo:nil];
            }
            //Note: No need to set *newValue here.
            return NO;
        }
    }
    

    (I've also noticed that the setter method receives an NSString, not an NSNumber. Is that normal?)

    Yes, unless you use a value transformer that transforms strings into numbers, connect a number formatter to the formatter outlet, or substitute an NSNumber for the NSString in your validation method.

    0 讨论(0)
  • 2020-12-29 01:03

    Like Ben mentioned, one way to do this is to attach an NSNumberFormatter to your textfield, which is pretty trivial to set up in interface builder and will likely Just Work™.

    If you don't like the modal dialogs NSNumberFormatter throws at your users when they enter non-numeric values, you can subclass NSNumberFormatter to implement different, ‘more forgiving’ formatting behavior. I think overriding – numberFromString: to strip out non-numeric characters before calling super's implementation should do the trick.

    Another approach is to create and register your own NSValueTransformer subclass to parse strings into NSNumbers and back, but I'd try using an NSNumberFormatter first since it's pretty clearly the class that has been designed for this exact purpose.

    More about value transformers

    0 讨论(0)
提交回复
热议问题