美文网首页
runtime全局过滤表情emoji

runtime全局过滤表情emoji

作者: 昵称nickName | 来源:发表于2018-06-06 17:53 被阅读0次

    https://my.oschina.net/5zx1Vm/blog/700546

    具体实现,导入全局的Category,这里叫UITextField+Emoji,覆盖+load函数(该函数在当前类读入内存时会收到消息),在该函数中通过Runtime替换初始化和Delegate相关函数,在初始化函数中,我们代理业务代码设置的Delegate,当用户有输入操作时,会触发我们代理的Delegate,在处理完Emoji校验之后,再路由给业务代码的Delegate。

    我们项目采用.pch做全局h导入,在这里我们导入UITextField+Emoji的Gategory
    /// 过滤Emoji字符

    import "UITextField+EmojiText.h"

    在.m中,我们在+load函数内替换相关函数指针,让原有函数指向我们实现的IMP

    void exchangeMethod(Class class, SEL oSEL, SEL nSEL)
    {
        Method oMethod = class_getInstanceMethod(class, oSEL);
        Method nMethod = class_getInstanceMethod(class, nSEL);// 验证当前实例是否实现originalSEL,避免返回父类SEL
        BOOL ok = class_addMethod(class, oSEL, method_getImplementation(nMethod), method_getTypeEncoding(nMethod));
        if (ok) {
            class_replaceMethod(class, nSEL, method_getImplementation(oMethod), method_getTypeEncoding(oMethod));
        } else {
            method_exchangeImplementations(oMethod, nMethod);
        }
    }
    
    + (void) load
    {
        // setDelegate,拦截Delegate设置,默认走Emoji过滤
        exchangeMethod([self class], @selector(setDelegate:), @selector(emoji_setDelegate:));
        // getDelegate,返回业务代码设置的Delegate,确保set和get统一
        exchangeMethod([self class], @selector(delegate), @selector(emoji_delegate));
        // 几种初始化情况
        exchangeMethod([self class], @selector(init), @selector(emoji_init));
        exchangeMethod([self class], @selector(initWithFrame:), @selector(emoji_initWithFrame:));
        exchangeMethod([self class], @selector(initWithCoder:), @selector(emoji_initWithCoder:));
        // 释放内部持有资源
    //    exchangeMethod([self class], @selector(dealloc), @selector(emoji_dealloc));
    }
    
    - (id) emoji_init
    {
        id ret = [self emoji_init];// 因为执行了函数指针替换,setDelegate会走emoji_setDelegate,这里调用setDelegate是为了确保没有设置delegate的业务代码同样过滤Emoji
        self.delegate = nil;return ret;
    }
    
    - (id) emoji_initWithFrame:(CGRect)frame
    {
        id ret = [self emoji_initWithFrame:frame];self.delegate = nil;return ret;
    }
    
    - (id) emoji_initWithCoder:(NSCoder *)aDecoder
    {
        id ret = [self emoji_initWithCoder:aDecoder];self.delegate = nil;return ret;
    }
    
    - (void) emoji_setDelegate:(id )delegate
    {
        // 如果没有设置过delegate,需要设置内部代理的Delegate,否则让替换内部originalDelegate
        id del = [self emoji_delegate];
        if (!del) {
            EmojiDelegate *emojiDelegate = [[EmojiDelegate alloc] initWithTextField:self];
            emojiDelegate.originalDelegate = delegate;
            [self emoji_setDelegate:emojiDelegate];
            self.strongDel = emojiDelegate;//给一个强引用,防止释放
        } else {
            EmojiDelegate *emojiDelegate = (EmojiDelegate *) del;
            emojiDelegate.originalDelegate = delegate;
        }
    }
    
    - (id )emoji_delegate
    {
        return ((EmojiDelegate *)[self emoji_delegate]).originalDelegate;
    }
    
    - (void)setStrongDel:(id)strongDel {
        objc_setAssociatedObject(self, @"strongDel", strongDel, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
    }
    

    下面是表情过滤方法

    @interface EmojiDelegate : NSObject
    
    @property(nonatomic, weak) UITextField *textField;
    @property(nonatomic, weak) id originalDelegate;
    @property(nonatomic, strong) NSString *prevText;// 上次的输入结果
    - (id) initWithTextField:(UITextField *)textField;
    @end
    
    @implementation EmojiDelegate
    - (id) initWithTextField:(UITextField *)textField
    {
        self = [super init];self.textField = textField;
        [textField addTarget:self action:@selector(textFieldDidChange:) forControlEvents:UIControlEventEditingChanged];return self;
    }
    - (void) dealloc
    {
        [_textField removeTarget:self action:@selector(textFieldDidChange:) forControlEvents:UIControlEventEditingChanged];
        self.originalDelegate = nil;
        self.prevText = nil;
    //    [super dealloc];
    }
    - (BOOL)textFieldShouldBeginEditing:(UITextField *)textField
    {
        if ([self.originalDelegate respondsToSelector:@selector(textFieldShouldBeginEditing:)]) {
            return [self.originalDelegate textFieldShouldBeginEditing:textField];
        }
        return YES;
    }
    - (void)textFieldDidBeginEditing:(UITextField *)textField
    {
        if ([self.originalDelegate respondsToSelector:@selector(textFieldDidBeginEditing:)]) {
            return [self.originalDelegate textFieldDidBeginEditing:textField];
        }
    }
    - (BOOL)textFieldShouldEndEditing:(UITextField *)textField
    {
        if ([self.originalDelegate respondsToSelector:@selector(textFieldShouldEndEditing:)]) {
            return [self.originalDelegate textFieldShouldEndEditing:textField];
        }
        return YES;
    }
    - (void)textFieldDidEndEditing:(UITextField *)textField
    {
        if ([self.originalDelegate respondsToSelector:@selector(textFieldDidEndEditing:)]) {
            return [self.originalDelegate textFieldDidEndEditing:textField];
        }
    }
    - (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
    {
        if (string.length == 0) {
            return YES;
        }/// 过滤emoji// 忽略系统默认的emoji键盘
        if ([[[textField textInputMode] primaryLanguage] isEqualToString:@"emoji"]) {
            return NO;
        }// 验证string的emoji字符
        if ([string containEmoji]) {
            return NO;
        }if ([self.originalDelegate respondsToSelector:@selector(textField:shouldChangeCharactersInRange:replacementString:)]) {
            return [self.originalDelegate textField:textField shouldChangeCharactersInRange:range replacementString:string];
        }
        return YES;
    }
    - (BOOL)textFieldShouldClear:(UITextField *)textField
    {
        if ([self.originalDelegate respondsToSelector:@selector(textFieldShouldClear:)]) {
            return [self.originalDelegate textFieldShouldClear:textField];
        }
        return NO;
    }
    - (BOOL)textFieldShouldReturn:(UITextField *)textField
    {
        if ([self.originalDelegate respondsToSelector:@selector(textFieldShouldReturn:)]) {
            return [self.originalDelegate textFieldShouldReturn:textField];
        }
        return NO;
    }
    

    过程中新的代理一直设置不上,EmojiDelegate初始化后就释放,后来想到UITextField的delegate是weak属性!!!!解决方法,又给分类加了一个strong属性的StrongDel,用它指向新初始化的EmojiDelegate。

    相关文章

      网友评论

          本文标题:runtime全局过滤表情emoji

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