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.