zoukankan      html  css  js  c++  java
  • UITextField多个代理对象

    项目中有个需求就是只能输入固定字符的文本框,如:价格文本框。只能输入数字和小数点,如果输入其他字符,则输入无效,即

    - (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
        return NO;
    }

    通常情况下会将字符判断的逻辑放在这个代理方法中判断,如果符合就返回YES ,如果不符合就返回NO。但是就算将判断的逻辑提炼出来,在VC的中还是要实现代理方法。或者自定义一个textField,使用一个通知UITextFieldTextDidChangeNotification来做这个逻辑判断。

    今天我提供的是另一个解决的思路,就是想办法让textField可以同时响应两个对象中的代理方法。即将CustomTextField必须要实现的代理直接放在一个Delegate类中,使用CustomTextField的人则不用关心代理的逻辑,而只实现他需要关注的代理就可以了。

    demo地址:

    https://github.com/DawnWdf/DWDoubleDelegateDemo.git

    大体思路如下:(VCD代表在viewcontroller里面设置textfield的代理,MD代表自定义代理,TF代表textField)

    1:设置TF代理为MD,MD配置属性originalDelegate为VCD

    2:获取TF所有代理及应该实现的代理方法

    3:如果VCD实现但是MD没有实现则进行实现方法的重新定向

    上代码吧,语言表达实在不行。

    @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。

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

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

  • 相关阅读:
    ASP.NET MVC preview 1升级到ASP.NET MVC preview 2的一些更改
    今天遇到一个非常奇怪的问题
    Microsoft ASP.NET MVC中Membership登陆的实现
    自己用的一个ASP.Net MVC分页拿出来分享下
    KnockoutJs学习笔记(一)
    KnockoutJs学习笔记(三)
    KnockoutJs学习笔记(二)
    KnockoutJs学习笔记(四)
    学习网站不定期更新
    一些好的网站
  • 原文地址:https://www.cnblogs.com/PhenixWang/p/7112434.html
Copyright © 2011-2022 走看看