How do I restrict a NSTextField
to allow only numbers/integers? I've found questions like this one, but they didn't help!
-
1http://stackoverflow.com/questions/4652689/restrict-nstextfield-input-to-numeric-only-nsnumberformatter – giorashc Aug 28 '12 at 14:39
-
@giorashc thank you, I found it, but it didn't help :( – JomanJi Aug 28 '12 at 15:06
-
1You need to specify _why_ the other questions you've found didn't help. – jscs Aug 28 '12 at 16:16
-
oh, sorry W'rkncacnter, I don't know where to put the code, the answer isn't clear.... (for me at least) – JomanJi Aug 28 '12 at 17:22
11 Answers
Try to make your own NSNumberFormatter
subclass and check the input value in -isPartialStringValid:newEditingString:errorDescription:
method.
@interface OnlyIntegerValueFormatter : NSNumberFormatter
@end
@implementation OnlyIntegerValueFormatter
- (BOOL)isPartialStringValid:(NSString*)partialString newEditingString:(NSString**)newString errorDescription:(NSString**)error
{
if([partialString length] == 0) {
return YES;
}
NSScanner* scanner = [NSScanner scannerWithString:partialString];
if(!([scanner scanInt:0] && [scanner isAtEnd])) {
NSBeep();
return NO;
}
return YES;
}
@end
And then set this formatter to your NSTextField
:
OnlyIntegerValueFormatter *formatter = [[[OnlyIntegerValueFormatter alloc] init] autorelease];
[textField setFormatter:formatter];

- 7,300
- 6
- 32
- 55
-
8In Interface Builder, drop an NSObject onto the xib and set it's class to be your custom formatter (like the above). Then set/drag the NSTextFields "formatter" outlet to that NSObject. Then you don't need any code to apply the formatter. – Ali May 22 '13 at 11:05
-
1It is working all fine.... but when ever i tried to enter multiple zeros(0)..like 000000.....its not accepting... any help pls??? – VSN Mar 10 '14 at 10:34
Swift 3 Version
import Foundation
class OnlyIntegerValueFormatter: NumberFormatter {
override func isPartialStringValid(_ partialString: String, newEditingString newString: AutoreleasingUnsafeMutablePointer<NSString?>?, errorDescription error: AutoreleasingUnsafeMutablePointer<NSString?>?) -> Bool {
// Ability to reset your field (otherwise you can't delete the content)
// You can check if the field is empty later
if partialString.isEmpty {
return true
}
// Optional: limit input length
/*
if partialString.characters.count>3 {
return false
}
*/
// Actual check
return Int(partialString) != nil
}
}
Use:
let onlyIntFormatter = OnlyIntegerValueFormatter()
myNsTextField.formatter = onlyIntFormatter

- 501
- 5
- 6
Here's a solution with filtering. Give a delegate and an outlet to textfield and set controlTextDidChange method.
- (void)controlTextDidChange:(NSNotification *)aNotification {
NSTextField *textfield = [notification object];
NSCharacterSet *charSet = [NSCharacterSet characterSetWithCharactersInString:@"0123456789"];
char *stringResult = malloc([textfield.stringValue length]);
int cpt=0;
for (int i = 0; i < [textfield.stringValue length]; i++) {
unichar c = [textfield.stringValue characterAtIndex:i];
if ([charSet characterIsMember:c]) {
stringResult[cpt]=c;
cpt++;
}
}
stringResult[cpt]='\0';
textfield.stringValue = [NSString stringWithUTF8String:stringResult];
free(stringResult);
}

- 11,454
- 9
- 54
- 64

- 3,715
- 2
- 29
- 29
Try this -
NSNumberFormatter *formatter = [[[NSNumberFormatter alloc] init] autorelease];
[formatter setNumberStyle:NSNumberFormatterDecimalStyle];
[textField setFormatter:formatter];

- 383
- 1
- 7
-
1Thank you for answering, but for some reason it still won't allow only numbers :( But i'll keep trying......btw, where's the code supposed too be? – JomanJi Aug 28 '12 at 15:28
Here is a Swift version:
override func isPartialStringValid(partialString: String, newEditingString newString: AutoreleasingUnsafeMutablePointer<NSString?>, errorDescription error: AutoreleasingUnsafeMutablePointer<NSString?>) -> Bool {
if (count(partialString.utf16)) {
return true
}
if (partialString.rangeOfCharacterFromSet(NSCharacterSet.decimalDigitCharacterSet().invertedSet) != nil) {
NSBeep()
return false
}
return true
}

- 7,217
- 2
- 34
- 63
-
1`string.utf16Count` is not available in swift 1.2 anymore. You should change it to `count(partialString.utf16)`. – yinkou May 27 '15 at 07:50
-
It's actually wrong on many levels. First, numbers aren't boolean convertible, and second, you want to check `isEmpty`. If the length of the string is greater than zero, you must fall through – Mazyod Nov 27 '15 at 06:55
In SWIFT, I do it this way
- Convert the text value to Int with Int()
- Check the converted value is not less than 0
If less than 0, display error message other accept the value
if ((Int(txtField.stringValue)) < 0){ // Display error message }

- 1,628
- 1
- 12
- 23

- 273
- 3
- 15
[Works with Swift 3.0.1]
As others suggested, subclass NumberFormatter
and override isPartialStringValid
method. The easiest way is to drop a NumberFormatter
object under your NSTextField
in xib/storyboard and update it's Custom Class
.
Next implementation allows only integers or blank value and plays a beep if string contains illegal characters.
class IntegerFormatter: NumberFormatter {
override func isPartialStringValid(_ partialString: String, newEditingString newString: AutoreleasingUnsafeMutablePointer<NSString?>?, errorDescription error: AutoreleasingUnsafeMutablePointer<NSString?>?) -> Bool {
// Allow blank value
if partialString.numberOfCharacters() == 0 {
return true
}
// Validate string if it's an int
if partialString.isInt() {
return true
} else {
NSBeep()
return false
}
}
}
String
's numberOfCharacters()
and isInt()
are methods added in an extension.
extension String {
func isInt() -> Bool {
if let intValue = Int(self) {
if intValue >= 0 {
return true
}
}
return false
}
func numberOfCharacters() -> Int {
return self.characters.count
}
}

- 7,559
- 3
- 41
- 46
Here is the steps to create the same....
Just create the ANYCLASS(called SAMPLE) with sub classing the NSNumberFormatter ...
in .m file write the following code...
- (BOOL)isPartialStringValid:(NSString *)partialString newEditingString:(NSString **)newString errorDescription:(NSString **)error {
// Make sure we clear newString and error to ensure old values aren't being used
if (newString) { *newString = nil;}
if (error) {*error = nil;}
static NSCharacterSet *nonDecimalCharacters = nil;
if (nonDecimalCharacters == nil) {
nonDecimalCharacters = [[NSCharacterSet decimalDigitCharacterSet] invertedSet] ;
}
if ([partialString length] == 0) {
return YES; // The empty string is okay (the user might just be deleting everything and starting over)
} else if ([partialString rangeOfCharacterFromSet:nonDecimalCharacters].location != NSNotFound) {
return NO; // Non-decimal characters aren't cool!
}
return YES;
}
Now.. in your Actual Class set the formatter to your NSTextField object like below...
NSTextField *mySampleTxtFld;
for this set the Formatter...
SAMPLE* formatter=[[SAMPLE alloc]init];// create SAMPLE FORMATTER OBJECT
self.mySampleTxtFld.delegate=self;
[self.mySampleTxtFld setFormatter:formatter];
Your done!!!

- 2,361
- 22
- 30
Swift 2.0 custom formatter with 0 instead of empty space :
class OnlyIntegerValueFormatter: NSNumberFormatter {
override func isPartialStringValid(partialString: String, newEditingString newString: AutoreleasingUnsafeMutablePointer<NSString?>, errorDescription error: AutoreleasingUnsafeMutablePointer<NSString?>) -> Bool {
if partialString.isEmpty {
newString.memory = "0"
return false
}
if Int(partialString) < 0 {
NSBeep()
return false
} else {
return true
}
}
}

- 5,026
- 1
- 28
- 32
in swift 5.7:
import Cocoa
class Main: NSViewController {
@IBOutlet weak var textfield: NSTextField!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
textfield.delegate = self
}
}
extension Main: NSTextFieldDelegate {
func controlTextDidChange(_ obj: Notification) {
let filtered = (obj.object as! NSTextField).stringValue.filter{"0123456789".contains($0)}
if filtered != (obj.object as! NSTextField).stringValue {
(obj.object as! NSTextField).stringValue = filtered
}
}
}
If you want to allow only specified characters to be entered, you can change the filter rules. like this:
let filtered = (obj.object as! NSTextField).stringValue.filter{"abcdefghijklmnopqrstuvwxyz".contains($0)}
Hope this helps you

- 11
- 2
// NSTextFieldNumberFormatter+Extension.swift
import Foundation
class TextFieldIntegerValueFormatter: NumberFormatter {
var maxLength: Int
init(maxLength: Int) {
self.maxLength = maxLength
super.init()
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func isPartialStringValid(_ partialString: String, newEditingString newString: AutoreleasingUnsafeMutablePointer<NSString?>?, errorDescription error: AutoreleasingUnsafeMutablePointer<NSString?>?) -> Bool {
// Ability to reset your field (otherwise you can't delete the content)
// You can check if the field is empty later
if partialString.isEmpty {
return true
}
// Optional: limit input length
if partialString.count > maxLength {
return false
}
// Actual check
return Int(partialString) != nil
}
}
//Need to call like:
myNsTextField.formatter = TextFieldIntegerValueFormatter(maxLength: 6)

- 2,225
- 2
- 24
- 36