提出问题:
ios项目经常遇到很多不同要求的textField, 比如这个要求只能输入数字, 那个要求只能输入英文字母....如果对每个textField实现delegate来判断,代码量过大. 有没有简化的方法?
方法步骤:
1.给UITextField新增一个属性fieldType, 用于区别textField的输入类型,就是通过Category, 新增一个动态关联属性(只能生成此属性的set和get方法,不可生成对应的成员变量_fieldType);
2.在APPdelegate中, 程序启动时, 给UITextField注册两个系统通知;
3.利用正则表达式, 限制输入的字符(这里以"只能输入数字"为例).
代码实现
@interface UITextField (FieldType)
//增加一个文本类型的属性(本质是仅仅添加了set/get方法,不会增加成员变量)
@property (nonatomic,copy) NSString *fieldType;
@end
#import "UITextField+FieldType.h"
#import <objc/runtime.h>
@implementation UITextField (FieldType)
static const void *tagKey = &tagKey;//自定义的关联标识
//set方法
-(void)setFieldType:(NSString *)fieldType{
//给UITextField新增一个"fieldType"的关联属性
//(1)给谁新增方法; (2)关联的唯一标识; (3)属性名; (4)关联策略,如retain,copy等.
objc_setAssociatedObject(self, tagKey, fieldType, OBJC_ASSOCIATION_COPY_NONATOMIC);
// @param object The source object for the association.
// @param key The key for the association.
// @param value The value to associate with the key key for object. Pass nil to clear an existing association.
// @param policy The policy for the association.
}
//get方法
-(NSString *)fieldType{
//根据'关联标识', 返回关联属性
return objc_getAssociatedObject(self, tagKey);
}
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
//程序一启动, 就立马注册通知.
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(beginEditingAction:) name:UITextFieldTextDidBeginEditingNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(infoAction:) name:UITextFieldTextDidChangeNotification object:nil];
return YES;
}
//第一个通知来得到我们开始编辑的TextField的原始值
-(void)beginEditingAction:(NSNotification *)notify{
UITextField *textField = (UITextField *)notify.object;
_textStr = textField.text;
}
//第二个通知来判断我们输入的字符串符不符合要求,我们首先需要一个通过正则表达式判断是否符合规范的方法
-(void)infoAction:(NSNotification *)notify{
UITextField *textField = (UITextField *)notify.object ;
/*
_textStr为我们输入字符串之前的TextField的值
**/
NSString *headStr = _textStr;
/**
判断用户是否进行了删除操作,如果进行了删除操作则该方法return
**/
if (textField.text.length < _textStr.length) {
_textStr = textField.text;
return;
}
/**
得到键入的字符串
**/
NSString *footStr = [textField.text substringFromIndex:_textStr.length];
/**
判断该textField需要满足校验
**/
if ([textField.fieldType isEqualToString:@"number"]) {
NSLog(@"此输入框我们需要校验的类型!");
if ([self validateAccount:footStr]) {
/**
当输入的字符串符合规范时把新输入的字符串添加到输入框显示的字符串中
**/
_textStr = [NSString stringWithFormat:@"%@%@",headStr,footStr];
}else{
/*
不符合规范时输入框的内容依然为我们输入字符串之前的值
**/
textField.text = headStr;
}
}else {
NSLog(@"此输入框不是我们想要的类型,不需要校验");
}
}
- (BOOL)validateAccount:(NSString *)textString{
NSString *number = @"^[0-9xX]+$";
NSPredicate *numberPre = [NSPredicate predicateWithFormat:@"SELF MATCHES %@",number];
return [numberPre evaluateWithObject:textString];
}
<br>
动态关联属性, 指的是为某个类新增一个"关联属性", 与属性的区别是不会生成一个_属性名的成员变量. 所以,Category只能新增方法.