Validate User Input in UITextField, with Smarts to Properly Manage Copy and Paste

Mon, Mar 1

I’ve written a short character validation method that you can use as a starting point for validating characters against a character set. For devices running iPhone OS 3.x and thus support copy/paste, this code will also validate characters pasted into a textfield, and if invalid characters are found in the buffer, the input is not accepted.

The idea is to break apart the incoming string into substrings, using the invalid character set as the characters to split the string. The result returned is an array of objects that have been divided by the invalid characters. If the array has more than one entry, at least one invalid characters was found.

One note, typically the incoming string is just a single character (as typed by the user). However, for cases where the user has pasted a string, the string will vary in length.

If you are a fan of regular expressions you could change up the code using a library such as RegexKitLite.

To use this code, add the method below in the class which is the delegate for the TextField.

 
// You can add/tailor the acceptable values here...
#define CHARACTERS          @" ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
#define CHARACTERS_NUMBERS  [CHARACTERS stringByAppendingString:@"1234567890"]
 
/*---------------------------------------------------
* Called whenever user enters/deletes character
*--------------------------------------------------*/
- (BOOL)textField:(UITextField *)textField 
    shouldChangeCharactersInRange:(NSRange)range 
    replacementString:(NSString *)string
{
  // These are the characters that are ~not~ acceptable
  NSCharacterSet *unacceptedInput =
    [[NSCharacterSet characterSetWithCharactersInString:CHARACTERS] invertedSet];
 
  // Create array of strings from incoming string using the unacceptable
  // characters as the trigger of where to split the string.
  // If array has more than one entry, there was at least one unacceptable character
  if ([[string componentsSeparatedByCharactersInSet:unacceptedInput] count] > 1)
    return NO;
  else 
    return YES;
}

You can adjust the character sets as you need to match the input requirements of your application. One more idea would be to manage the character sets inside the method, using a flag to indicate which set to compare against.

5 comments

After this step: “The result returned is an array of objects that have been divided by the invalid characters.” — why not just check if ([array count > 1) ? If invalid characters are found, won’t there be 2 or more objects in the array?

by Michelle on Mar 1, 2010. Reply #

Thanks Michelle, good catch, I’ve updated the code example based on your tip.

by John Muchow on Mar 1, 2010. Reply #

Nice not. Two things –

First, the concatenation of two constant strings can be done at compile time without resort to stringByAppendingString:. Just write them one after another, just like regular strings in C.

#define CHARACTERS_NUMBERS CHARACTERS @”1234567890″

For extra tidiness, you could enclose the definition in parentheses, but as above you could concatenate yet more things onto CHARACTERS_NUMBERS.

Second, I have a problem with if ( something ) return NO; else return YES; That is just simply
return !(something). So in this case:

return [[string componentsSeparatedByCharactersInSet:unacceptedInput] count] == 1;

This makes the condition being asserted even more clear.

by Scott Marks on Sep 14, 2010. Reply #

Thanks John, it helped me a lot !

by Bruno on Feb 29, 2012. Reply #

searchBarSearchButtonClicked doesn’t work together with shouldChangeTextInRange

I have the following UISearchBar delegate method that works by its own (it’s called when it’s alone).

-(void)searchBarSearchButtonClicked:(UISearchBar *)searchBar{
[self downloadFruits:searchBar.text];
[self.view endEditing:YES];
}

When I added another UISearchBar delegate method the previous one stopped working (it’s not called anymore).

#define CHARACTERS @”ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz _-.”
#define CHARACTERS_NUMBERS [CHARACTERS stringByAppendingString:@"1234567890"]

-(BOOL)searchBar:(UISearchBar *)searchBar shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text{
NSCharacterSet *unacceptedInput =
[[NSCharacterSet characterSetWithCharactersInString:CHARACTERS_NUMBERS] invertedSet];
// If array has more than one entry, there was at least one unacceptable character
if ([[text componentsSeparatedByCharactersInSet:unacceptedInput] count] > 1)
return NO;
else
return YES;
}

Each of them works well alone but together the first one (Search button) is not called

by Alex on Feb 26, 2013. Reply #

Leave a Comment