美文网首页
用Method Swizzling 限制textfield 输入

用Method Swizzling 限制textfield 输入

作者: 随便你好啦 | 来源:发表于2019-05-08 17:35 被阅读0次

最近公司有个需求,要在所有的输入框内限制emoji表情和特殊字符的输入,因为公司的项目已经开发了有半年了,所有输入的地方数不胜数,于是我只能通过Method Swizzling来实现这个需求。

其实在项目中大量使用Method Swizzling的代码会导致后期项目难以维护,所以一般我在使用Method Swizzling的时候会考虑是否有其他的解决方案。

其实Method Swizzling的使用真的很简单,举个简单的例子,就是直接让字体跟屏幕宽度变化。替换系统的设置字体的方法。

+ (void)load{
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        SEL originSel = @selector(systemFontOfSize:);
        Method originMethod = class_getClassMethod(object_getClass(self), originSel);
        
        SEL customSel = @selector(customFontOfSize:);
        Method customMethod = class_getClassMethod(object_getClass(self), customSel);
        
        BOOL success = class_addMethod(object_getClass(self), originSel, method_getImplementation(customMethod), method_getTypeEncoding(customMethod));
        
        if (success) {
            class_replaceMethod(object_getClass(self), customSel, method_getImplementation(originMethod), method_getTypeEncoding(originMethod));
        }else{
            method_exchangeImplementations(originMethod, customMethod);
        }
    });
}

+ (UIFont *)customFontOfSize:(CGFloat )size{
    CGFloat scale = [UIScreen mainScreen].bounds.size.width / 375.0;
    CGFloat tepSize = size * scale;
    return [self customFontOfSize:tepSize];
}

接下来,我们就可以考虑怎么限制textfield或者textview的输入了。
新建一个category


image.png

引入头文件:


image.png
第一步获取获取交换其代理方法:
+ (void)load{
    Class selfClass = [self class];
    //注意这里是实例方法
    SEL originSel = @selector(setDelegate:);
    Method originDelegate = class_getInstanceMethod(selfClass, originSel);
    
    SEL customSel = @selector(setCustomDelegate:);
    Method customDelegate = class_getInstanceMethod(selfClass, customSel);
    
    method_exchangeImplementations(originDelegate, customDelegate);
}

- (void)setCustomDelegate:(id<UITextFieldDelegate>)delegate{
    //注意:这里不会引起死循环,方法已经交换过来了
    [self setCustomDelegate:delegate];
    [self exchangeDelegate:delegate];
}

第二步:交换代理对象的方法和被替换的方法

//hook 代理对象的方法
- (void)exchangeDelegate:(id<UITextFieldDelegate>)delegate{
    SEL originSel = @selector(textField:shouldChangeCharactersInRange:replacementString:);
    Method originMethod = class_getInstanceMethod([delegate class], originSel);
    
    SEL swizzleSel = @selector(swizzleTextField:shouldChangeCharactersInRange:replacementString:);
    Method swizzleMethod = class_getInstanceMethod([self class], swizzleSel);
    
    BOOL success = class_addMethod([delegate class], originSel, method_getImplementation(swizzleMethod), method_getTypeEncoding(swizzleMethod));
    if (success) {
        class_replaceMethod([self class], swizzleSel, method_getImplementation(originMethod), method_getTypeEncoding(originMethod));
    }else{
        method_exchangeImplementations(originMethod, swizzleMethod);
    }
}

- (BOOL)swizzleTextField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string{
    NSLog(@"swizzleTextField input == %@", string);
    if ([string isEqualToString:@"#"] || [string isEqualToString:@"%"]) {
        NSLog(@"不能输入特殊字符");
        return NO;
        
    }
    return  YES;
}

但有一点就是textview 和textfield的代理必须要本类实现,不然无法获取到代理对象,也就无法交换其方法。

self.view.backgroundColor = [UIColor whiteColor];
    UITextField * field = [[UITextField alloc]initWithFrame:CGRectMake(20, 200, 300, 30)];
    field.borderStyle =  UITextBorderStyleRoundedRect;
    //这里代理必须实现,因为需要hook需要获取代理对象
    field.delegate = self;
    [self.view addSubview:field];

你可以自己扩展自己想要限制的字符。
demo 地址

相关文章

网友评论

      本文标题:用Method Swizzling 限制textfield 输入

      本文链接:https://www.haomeiwen.com/subject/skmvoftx.html