整体的目录结构
分批次描述:
cell 文件夹
没有必要一一讲述,这里就是不同元素,每个元素其实都是UITableViewCell,但是为了统一封装都继承了XLFormBaseCell,最后在统一继承UITableViewCell
Controllers 文件夹
Descriptors(描述) 文件夹
Helpers(分类) 文件夹
Validation(限制) 文件夹
里面可以集成对各个输入的一些限制判断,在其中可以通过正则表达式来限制。
XLFormRegexValidator类为解析正正则表达式,判断出是否符合输入限制,其核心代码
-(XLFormValidationStatus *)isValid: (XLFormRowDescriptor *)row {
if (row != nil && row.value != nil) {
// we only validate if there is a value
// assumption: required validation is already triggered
// if this field is optional, we only validate if there is a value
id value = row.value;
if ([value isKindOfClass:[NSNumber class]]){
value = [value stringValue];
}
if ([value isKindOfClass:[NSString class]] && [value length] > 0) {
//通过谓词这种高级特性判断输入内容是否符合标准
BOOL isValid = [[NSPredicate predicateWithFormat:@"SELF MATCHES %@", self.regex] evaluateWithObject:[value stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]]];
//将结果建立一个模型
return [XLFormValidationStatus formValidationStatusWithMsg:self.msg status:isValid rowDescriptor:row];
}
}
return nil;
};
XLFormValidationStatus 其实就是一个是否符合标准的模型。
XLFormValidator判断输入是否符合标准的集合,所有的规则都在其中编写,可以做到很好的复用。
XLFormValidatorProtocol所有的限制规则都要遵守该协议。
下面简述一个限制的判断过程,已判断输入是否为邮箱为例:
首先在创建界面界面阶段要先加上对该条的判断规则
[row addValidator:[XLFormValidator emailValidator]];
然后再** XLFormValidator**中实现该方法
+(XLFormValidator *)emailValidator
{
return [XLFormRegexValidator formRegexValidatorWithMsg:NSLocalizedString(@"邮箱地址输入有误", nil) regex:@"[A-Z0-9a-z._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,4}"];
}
运行时该条限定条件会添加到该元素的validators 数组中,也就是说,同一个元素可以存在多条限制
-(void)addValidator:(id)validator
{
if (validator == nil || ![validator conformsToProtocol:@protocol(XLFormValidatorProtocol)])
return;
if(![self.validators containsObject:validator]) {
[self.validators addObject:validator];
}
}
在提交表单的时候,可以进行检查
NSArray * validationErrors = [self formValidationErrors];
if (validationErrors.count > 0){
[self showFormValidationError:[validationErrors firstObject]];
return;
}
跳来跳去会跳到-(NSArray *)localValidationErrors:(XLFormViewController *)formViewController
函数,内部会把所有元素挨个遍历一遍寻找所有的,把所有不合格的输入都挑出来其中遍历元素的是[row doValidation]
方法
- (BOOL)valueIsEmpty
{
return self.value == nil || [self.value isKindOfClass:[NSNull class]] || ([self.value respondsToSelector:@selector(length)] && [self.value length]==0) ||
([self.value respondsToSelector:@selector(count)] && [self.value count]==0);
}
-(XLFormValidationStatus *)doValidation
{
XLFormValidationStatus *valStatus = nil;
if (self.required) { //判断输入是否为必须输入,如果为非必输则跳过
// do required validation here
if ([self valueIsEmpty]) {//判断元素是否为空
valStatus = [XLFormValidationStatus formValidationStatusWithMsg:@"" status:NO rowDescriptor:self];
NSString *msg = nil;
if (self.requireMsg != nil) {
msg = self.requireMsg;
} else {
// default message for required msg
msg = NSLocalizedString(@"%@ can't be empty", nil);
}
if (self.title != nil) {
valStatus.msg = [NSString stringWithFormat:msg, self.title];
} else {
valStatus.msg = [NSString stringWithFormat:msg, self.tag];
}
return valStatus;
}
}
// custom validator 遍历限制规则
for(id v in self.validators) {
if ([v conformsToProtocol:@protocol(XLFormValidatorProtocol)]) {
XLFormValidationStatus *vStatus = [v isValid:self];//实现协议的方法 生成一个是否成功的模型
// fail validation
if (vStatus != nil && !vStatus.isValid) {
return vStatus;
}
valStatus = vStatus;
} else {
valStatus = nil;
}
}
return valStatus;
}
根据这一些列操作就可以判断出是否输入是否符合限制
/**
遍历所有元素返回不符合输入规则的元素,并且返回相应的错误信息
@param formViewController formViewController description
@return return value description
*/
-(NSArray *)localValidationErrors:(XLFormViewController *)formViewController {
NSMutableArray * result = [NSMutableArray array];
for (XLFormSectionDescriptor * section in self.formSections) {
for (XLFormRowDescriptor * row in section.formRows) {
XLFormValidationStatus* status = [row doValidation];
if (status != nil && (![status isValid])) {
NSDictionary *userInfo = @{ NSLocalizedDescriptionKey: status.msg,
XLValidationStatusErrorKey: status };
NSError * error = [[NSError alloc] initWithDomain:XLFormErrorDomain code:XLFormErrorCodeGen userInfo:userInfo];
if (error){
[result addObject:error];
}
}
}
}
return result;
}