实时验证与结束验证是有区别的,它们的约束规则不也不一样,准备来说:结果验证的约束规则是实时验证的约束规则的一个特例;
如:一个输入框有如下的字符要求:输入字符为5位数字;这是一个结果验证的约束,但是在输入验证时,我们必须允许字符个数小于5个;
所以实时验证要比结束验证麻烦一些!
实时验证UITextField和UITextView中的内容有两种方案:
- 通过响应式编程,需要用响应工编程框架,如:RxSwift;
- 实现UITextField和UITextView的代理方法,在该代理方法中测试每一次的输入;
由于由于UITextField和UITextView的实时验证是经常被用到的,并且若想通过代理方法实现一个完美且全面的实时验证是需要久经测试和修改的,为了避免每次都要重新思考和设计,我就把记录在此;
因为要实时验证输入字符,所以需要在以下方法中验证:
UITextFieldDelegate:
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string;
UITextViewDelegate:
- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text;
因为UITextField和UITextView的输入变化的代理方法一样,所以对UITextField和UITextView和实时验证的代码逻辑是完全一样的,只需要更改变个别变量名字即可,本篇就以UITextField为例进行详解,具体逻辑如下:
//假设有多个输入框需要进行实时验证,则分别定义它们的tag值;
#define Tag_TF1 101 //输入框的tag
#define Tag_TF2 102 //输入框的tag
#define MaxLength 10 //输入字符允许的最大长度
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
//生成改变后的字符串
NSMutableString * text = [NSMutableString stringWithString:textField.text];
[text replaceCharactersInRange:range withString:string];
if (text.length == 0) {
//允许清空字符串
return YES;
}
BOOL shouldChange = YES; //用于保存是否允许此次改变
switch (textField.tag) {
case Tag_TF1: //被检查的输UITextField的tag
{//判断最大长度和正则:用于需要限制长度 且 正则中描述不了长度 的情况
shouldChange = text.length <= MaxLength; //判断最大长度
if (shouldChange) {
//用正则表达式来验证是否符合模式要求;
// matchesRegEx:方法是我给NSString类扩展的一方法,用来验证字符是否符合正则表达式的,它的具体实现会在下面给出;
shouldChange = [text matchesRegEx:RegEx_1];
}
}
break;
case Tag_TF2:
{//仅判断正则:用于不限制长度 或者 正则里能描述长度 的情况
shouldChange = [text matchesRegEx:RegEx_2]; //判断正则
}
break;
default:
break;
}
return shouldChange;
}
上段代码中NSString的扩展方法matchesRegEx:
的具体实现如下:
NSString(BYExtension).m文件
/**
测试并返回是接收者是否匹配指定的正则表达式
备注:不能匹配空字符串
@param regEx 正则表达式
@return 是否匹配指定的正则表达式
*/
-(BOOL)matchesRegEx:(NSString *)regEx {
NSRange matchesRange = [self rangeOfString:regEx options:NSRegularExpressionSearch];
return matchesRange.length > 0;
}