UITextField多個代理對象

項目中有個需求就是隻能輸入固定字符的文本框,如:價格文本框。只能輸入數字和小數點,若是輸入其餘字符,則輸入無效,即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。

語言表達能力弱雞,要是有大神能看懂,就請幫忙找找不足什麼的吧!

 

絕對原創,如要轉載請註明出處。

相關文章
相關標籤/搜索