I am new to iOS and am baffled by the behavior of my following code. I want to validate a zip code and throw an alert if the user inputs more that 5 digits. I am using the number keyboard to ensure that I don't get anything but nums.
The alert throws at the 6th digit, which is what I want. If I hit the 'back button' to delete the last digit, on positions 0-3, it behaves just fine and deletes the last digit. If I hit the 'back button' on position 4, the alert throws. What am I doing wrong? How do I delete the 5th digit (postion 4 in the array)?
Thanks
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(开发者_JS百科NSString *)string
{
if ([zipText.text length] <= 4)
{
return YES;
}
else
{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Zip Code Limit" message:@"The system only requires a 5 digit zip code." delegate:nil cancelButtonTitle:@"Close" otherButtonTitles:nil, nil];
[alert show];
[alert release];
return NO;
}
}
You're testing based on the text field's previous content, not the content that would exist after the edit. You want to test based on what the content is after the edit.
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range
replacementString:(NSString *)string
{
NSString *oldString = textField.text;
NSString *newString = [oldString stringByReplacingCharactersInRange:range
withString:string];
if ([newString length] <= 5) {
return YES;
} else {
// do alert stuff
return NO;
}
}
This technique has the benefit of working with comparisons other than length. You just check the actual result of the edit before approving it. It's much simpler than trying to figure out what key was pressed.
You may want to make a habit of not referring to your variable (like zipTest) in delegate methods. Use the text field parameter, just in case you're the delegate of multiple text fields.
You need a more sophisticated test. Your current test says: "if there are four or fewer characters in zipText.text, allow the change." It should say: "if the user's change would result in more than 5 characters, disallow the change." In other words, don't reject the change if the user is trying to delete the fifth character.
BTW, your title is misleading. The operator is working exactly as expected: [zipText.text length] <= 4
fails as expected when the length is 5.
The problem is that the function - (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
is triggered before updating the text field value. What you need to do is check if replacementString
is actually the backspace character and just return YES
. If it's not than check to see if the length of the string is 5 and return NO
if it is.
You can do all this as follows:
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
if ([string characterAtIndex:0] == 10)
{
return YES;
}
else if ([zipText.text length] >= 5)
{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Zip Code Limit" message:@"The system only requires a 5 digit zip code." delegate:nil cancelButtonTitle:@"Close" otherButtonTitles:nil, nil];
[alert show];
[alert release];
return NO;
}
return YES;
}
Hope this helps.
If I understand correctly, you want to allow 5 digits long numbers (positions 0-4, length: 5), yet with if ([zipText.text length] <= 4)
the longest numer you accept can be only 4 digits long (positions 0-3, length: 4). You should change if ([zipText.text length] <= 4)
to if ([zipText.text length] <= 5)
.
精彩评论