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。

语言表达能力弱鸡,要是有大神能看懂,就请帮忙找找不足什么的吧!

 

绝对原创,如要转载请注明出处。

相关文章
相关标签/搜索