Your checks are all wrong. You don't want to check the length of the current text, you want to check the length of what the text would be if the change was allowed.
Try this:
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
NSString *newText = [textField.text stringByReplacingCharactersInRange:range withString:string];
if (textField.tag == 2) {
return newText.length <= 2; // only allow 2 or less characters
} else if (textField.tag == 3) {
return newText.length <= 1; // only allow 1 or less characters
} else {
return YES;
}
}