項目中有個需求就是隻能輸入固定字符的文本框,如:價格文本框。只能輸入數字和小數點,若是輸入其餘字符,則輸入無效,即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。
語言表達能力弱雞,要是有大神能看懂,就請幫忙找找不足什麼的吧!
絕對原創,如要轉載請註明出處。