How would I go about allowing inputting only alphanumeric characters in an iOS UITextField?
 
    
    - 20,617
- 19
- 137
- 193
 
    
    - 1,345
- 2
- 11
- 26
7 Answers
Use the UITextFieldDelegate method -textField:shouldChangeCharactersInRange:replacementString: with an NSCharacterSet containing the inverse of the characters you want to allow. For example:
// in -init, -initWithNibName:bundle:, or similar
NSCharacterSet *blockedCharacters = [[[NSCharacterSet alphanumericCharacterSet] invertedSet] retain];
- (BOOL)textField:(UITextField *)field shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)characters
{
    return ([characters rangeOfCharacterFromSet:blockedCharacters].location == NSNotFound);
}
// in -dealloc
[blockedCharacters release];
Note that you’ll need to declare that your class implements the protocol (i.e. @interface MyClass : SomeSuperclass <UITextFieldDelegate>) and set the text field’s delegate to the instance of your class.
 
    
    - 57,021
- 16
- 130
- 131
- 
                    You mean: return [characters rangeOfCharacterFromSet:blockedCharacters].location==NSNotFound; – Sagiftw Feb 28 '12 at 14:30
- 
                    Any particular reason that you inverted the alphanumericCharacter set? Couldn't you remove the invertedSet and then change your return test to != NSNotFound? Just curious as I've got some logic happening in there besides just the return – nbsp Jan 07 '14 at 22:30
- 
                    3Yep—if multiple characters get entered at once (e.g. when pasting text), checking against the non-inverted set will allow the change if there’s **any** alphanumeric character in the replacement text, even if they’re not **all** alphanumeric. – Noah Witherspoon Jan 07 '14 at 22:43
Swift 3 version
Currently accepted answer approach:
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
    // Get invalid characters
    let invalidChars = NSCharacterSet.alphanumerics.inverted
    // Attempt to find the range of invalid characters in the input string. This returns an optional.
    let range = string.rangeOfCharacter(from: invalidChars)
    if range != nil {
        // We have found an invalid character, don't allow the change
        return false
    } else {
        // No invalid character, allow the change
        return true
    }
}
Another equally functional approach:
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
    // Get invalid characters
    let invalidChars = NSCharacterSet.alphanumerics.inverted
    // Make new string with invalid characters trimmed
    let newString = string.trimmingCharacters(in: invalidChars)
    if newString.characters.count < string.characters.count {
        // If there are less characters than we started with after trimming
        // this means there was an invalid character in the input. 
        // Don't let the change go through
        return false
    } else {
        // Otherwise let the change go through
        return true
    }
}
 
    
    - 2,584
- 1
- 25
- 34
- 
                    
- 
                    @MarksCode you're correct. I updated that approach to work with pasted characters. I also added the same approach that the accepted answer uses. – teradyl May 05 '17 at 22:42
This is how I do it:
// Define some constants:
#define ALPHA                   @"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
#define NUMERIC                 @"1234567890"
#define ALPHA_NUMERIC           ALPHA NUMERIC
// Make sure you are the text fields 'delegate', then this will get called before text gets changed.
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
    // This will be the character set of characters I do not want in my text field.  Then if the replacement string contains any of the characters, return NO so that the text does not change.
    NSCharacterSet *unacceptedInput = nil;
    // I have 4 types of textFields in my view, each one needs to deny a specific set of characters:
    if (textField == emailField) {
        //  Validating an email address doesnt work 100% yet, but I am working on it....  The rest work great!
        if ([[textField.text componentsSeparatedByString:@"@"] count] > 1) {
            unacceptedInput = [[NSCharacterSet characterSetWithCharactersInString:[ALPHA_NUMERIC stringByAppendingString:@".-"]] invertedSet];
        } else {
            unacceptedInput = [[NSCharacterSet characterSetWithCharactersInString:[ALPHA_NUMERIC stringByAppendingString:@".!#$%&'*+-/=?^_`{|}~@"]] invertedSet];
        }
    } else if (textField == phoneField) {
        unacceptedInput = [[NSCharacterSet characterSetWithCharactersInString:NUMERIC] invertedSet];
    } else if (textField == fNameField || textField == lNameField) {
        unacceptedInput = [[NSCharacterSet characterSetWithCharactersInString:ALPHA] invertedSet];
    } else {
        unacceptedInput = [[NSCharacterSet illegalCharacterSet] invertedSet];
    }
    // If there are any characters that I do not want in the text field, return NO.
    return ([[string componentsSeparatedByCharactersInSet:unacceptedInput] count] <= 1);
}
Check out the UITextFieldDelegate Reference too.
 
    
    - 51,908
- 16
- 134
- 170
- 
                    That's really helpful. Only thing I added was ` if ( ( [string isEqualToString:@"@"] ) && (range.location == 0 ) ) { unacceptedInput = [NSCharacterSet characterSetWithCharactersInString:@"@"]; }` inside the emailField branch to prevent @ being used to start an email address – Ryan Aug 13 '12 at 15:36
I found a simple and working answer and want to share:
connect your UITextField for the event EditingChanged to following IBAction
-(IBAction) editingChanged:(UITextField*)sender
{    
    if (sender == yourTextField)
    {
        // allow only alphanumeric chars
        NSString* newStr = [sender.text stringByTrimmingCharactersInSet:[[NSCharacterSet alphanumericCharacterSet] invertedSet]];
        if ([newStr length] < [sender.text length])
        {
            sender.text = newStr;
        }
    }
}
 
    
    - 1,345
- 2
- 11
- 26
- 
                    A question - is comparing lengths any better than just comparing contents? Unless length is actually stored in the NSString object, I would imagine either way that the comparison would take `m + n` time, where `m` is the length of `newStr` and `n` is the length of `sender.text`. – ArtOfWarfare Oct 01 '14 at 00:41
The RegEx way in Swift:
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
     if string.isEmpty {
         return true
     }
     let alphaNumericRegEx = "[a-zA-Z0-9]"
     let predicate = NSPredicate(format:"SELF MATCHES %@", alphaNumericRegEx)
     return predicate.evaluate(with: string)
}
 
    
    - 4,541
- 2
- 26
- 53
For Swift: Connect your UITextField for the event EditingChanged to following IBAction:
@IBAction func ActionChangeTextPassport(sender:UITextField){
    if sender == txtPassportNum{
        let newStr = sender.text?.stringByTrimmingCharactersInSet(NSCharacterSet.alphanumericCharacterSet().invertedSet)
        if newStr?.characters.count < sender.text?.characters.count{
            sender.text = newStr
        }
    }
}
 
    
    - 645
- 7
- 6
