美文网首页
runtime实操

runtime实操

作者: monk | 来源:发表于2016-06-28 14:34 被阅读26次
    runtime很早以前就听说过,也试着写过一些demo,但是总感觉在应用中用不上,或者说不知道怎么使用;最初接触的是叫Method Swizzling的东西,下面先讲讲Method Swizzling;
    编程有一种叫做面向切片编程AOP,具体可以定义可以去wiki查看,大概就是把一些碎片的代码跟主要功能分离;有个比较好的例子(这例子比较深刻)就是点击按钮或者进入某些特定界面,将这些用户习惯发送到服务器做大数据,这些逻辑实际上与应用逻辑没关系,所以让他们占据在整个app中显得不合适,具体看看实例:
    

    Method Swizzling原理
    每个类都维护一个方法(Method)列表,Method则包含SEL和其对应IMP的信息,方法交换做的事情就是把SEL和IMP的对应关系断开,并和新的IMP生成对应关系。
    交换前:Asel->AImp Bsel->BImp
    交换后:Asel->BImp Bsel->AImp
    实操:

    引入runtime,创建button实例

    #import <objc/runtime.h>
    @interface UIButton (ButtonSwizzling)
    
    @end
    

    .m文件实现:

    #import "ButtonSwizzling.h"
    @implementation UIButton (ButtonSwizzling)
    //应该尽可能在+load方法中实现,这样可以保证方法一定会调用且不会出现异常
    +(void)load {
        static dispatch_once_t onceToken;
        dispatch_once(&onceToken,^{
                  Class selfClass = [self class];
                  SEL originSEL = @selector(endTrackingWithTouch:withEvent:);
                 //获取SEL的方法
                 Method originMethod = class_getInstanceMethod(selfClass, originSEL);
                 SEL newSEL = @selector(newendTrackingWithTouch:withEvent:);
                 Method newMethod = class_getInstanceMethod(selfClass, newSEL);
                 //class_addMethod是给方法添加实现;getImplementation是获取方法的实现;getTypeEncoding获取实现的编码类型;
                 //先尝试給源方法添加实现,这里是为了避免源方法没有实现的情况
                 bool succ = class_addMethod(selfClass, newSEL, method_getImplementation(originMethod), method_getTypeEncoding(originMethod));
                 if (succ) {
                                 //取代实现
                                //添加成功:将源方法的实现替换到交换方法的实现
                                 class_replaceMethod(selfClass, newSEL, method_getImplementation(originMethod),      method_getTypeEncoding(originMethod));
                 } else {
                               //交换两个方法的实现
                               //添加失败:说明源方法已经有实现,直接将两个方法的实现交换即可
                               method_exchangeImplementations(originMethod, newMethod);
              }
          });
    }
    - (void)newendTrackingWithTouch:(nullable UITouch *)touch withEvent:(nullable UIEvent *)event {
            NSLog(@"BUTTON 方法改变啦");
           //事实上这里不是死循环哦,已经被替换成sendAction:to:forEvent:
           [self newendTrackingWithTouch:touch withEvent:event];
    }
    @end
    

    这样你点击button能看到console输出"BUTTON 方法改变啦"!!
    封装swizzling有个很出名的库,叫ASPECT!有兴趣的可以去看看,不过感觉也没差

    相关文章

      网友评论

          本文标题:runtime实操

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