项目中有个需求就是只能输入固定字符的文本框,如:价格文本框。只能输入数字和小数点,若是输入其余字符,则输入无效,即git
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string { return NO; }
一般状况下会将字符判断的逻辑放在这个代理方法中判断,若是符合就返回YES ,若是不符合就返回NO。可是就算将判断的逻辑提炼出来,在VC的中仍是要实现代理方法。或者自定义一个textField,使用一个通知UITextFieldTextDidChangeNotification来作这个逻辑判断。github
今天我提供的是另外一个解决的思路,就是想办法让textField能够同时响应两个对象中的代理方法。即将CustomTextField必需要实现的代理直接放在一个Delegate类中,使用CustomTextField的人则不用关心代理的逻辑,而只实现他须要关注的代理就能够了。ui
demo地址:atom
https://github.com/DawnWdf/DWDoubleDelegateDemo.gitspa
大致思路以下:(VCD表明在viewcontroller里面设置textfield的代理,MD表明自定义代理,TF表明textField)代理
1:设置TF代理为MD,MD配置属性originalDelegate为VCDcode
2:获取TF全部代理及应该实现的代理方法orm
3:若是VCD实现可是MD没有实现则进行实现方法的从新定向对象
上代码吧,语言表达实在不行。blog
@interface MyCustomTextField() @property (nonatomic, strong) MyTextFieldDelegate *currentDelegate; @end @implementation MyCustomTextField - (instancetype)initWithFrame:(CGRect)frame { self = [super initWithFrame:frame]; if (self) { MyTextFieldDelegate *del = [[MyTextFieldDelegate alloc] init];; del.textField = self; self.currentDelegate = del; self.delegate = (id)self.currentDelegate; } return self; } - (void)setDelegate:(id)delegate{ if ([delegate isMemberOfClass:[MyTextFieldDelegate class]]) { [super setDelegate:delegate]; return; } self.currentDelegate.originDelegate = delegate; } @end
设置不一样的代理,欺骗一下使用者。
- (void)setOriginDelegate:(id)originDelegate { _originDelegate = originDelegate; [self dw_allProtocolMethodImplementation]; } - (void)dw_allProtocolMethodImplementation{ //协议须要实现的方法 unsigned int protocolCount = 0; //获取当前类全部的协议 __unsafe_unretained Protocol **allP = class_copyProtocolList(self.class, &protocolCount); for (int i = 0; i < protocolCount; i++) { Protocol *protocol = allP[i]; BOOL conform = class_conformsToProtocol(self.class, protocol); if (conform) { unsigned int protocolMethodCount = 0; //获取协议方法描述 struct objc_method_description *protocolDes = protocol_copyMethodDescriptionList(protocol, NO, YES, &protocolMethodCount); for (int i = 0; i < protocolMethodCount; i++) { struct objc_method_description protocolObject = protocolDes[i]; SEL selector = protocolObject.name; //当前类是否实现此方法 BOOL isResponse = class_respondsToSelector(self.class, selector); //originalDelegate是否实现此方法 BOOL isOriginalResponse = class_respondsToSelector([self.originDelegate class], selector); if ((!isResponse) && isOriginalResponse) { //若是当前类没有实现可是originalDelegate实现了 则替换 Method originalMethod = class_getInstanceMethod([self.originDelegate class], selector); class_replaceMethod(self.class, selector, class_getMethodImplementation([self.originDelegate class], selector), method_getTypeEncoding(originalMethod)); } } } } }
runtime拿一下代理方法,而且实现方法替换一下
这样在MD和VCD中的代理则都会执行了。
这个思路用来解决textfield的问题没有明显优点,毕竟textfield的代理少,而且还有通知的方法能够解决。
可是若是用来解决像uitableview的封装问题,优点就比较明显了。好比在cell类型比较多的状况下,若是使用代理里面作判断的方式,那么每个代理方法里面都会有不少if else的判断,相对较好的办法是将经常使用的代理按照cell的种类进行一个封装。这样一种cell的全部处理,包括cell的ID cell对应的xib cell的高度等都在一个block或者代码段中执行,可读性会比较高。可是坏处就是所有的代理方法的实现都要重定向,至关麻烦,这个blog的思路就是用来解决这个问题的。若是之后不开心了,就写个这样的demo。
语言表达能力弱鸡,要是有大神能看懂,就请帮忙找找不足什么的吧!
绝对原创,如要转载请注明出处。