美文网首页
Objective-C之Method Swizzle

Objective-C之Method Swizzle

作者: RichieQ | 来源:发表于2017-07-24 16:55 被阅读0次

    一、原理
    我们平时编写的OC代码,底层都是基于Runtime来实现的。Runtime又叫运行时,是一套底层的C语言API,其为iOS内部的核心之一。
    1). 在没有一个类的实现源码的情况下,想改变其中一个方法的实现,除了继承它重写、和借助类别重名方法暴力抢先之外,还有更加灵活的方法 Method Swizzle。
    2). Method Swizzle 指的是改变一个已存在的选择器对应的实现的过程。OC中方法的调用能够在运行时通过改变,通过改变类的调度表中选择器到最终函数间的映射关系。
    3). 在OC中调用一个方法,其实是向一个对象发送消息,查找消息的唯一依据是selector的名字。利用OC的动态特性,可以实现在运行时偷换selector对应的方法实现。
    4). 每个类都有一个方法列表,存放着selector的名字和方法实现的映射关系。IMP有点类似函数指针,指向具体的方法实现。
    5). 我们可以利用 method_exchangeImplementations 来交换2个方法中的IMP。
    6). 我们可以利用 class_replaceMethod 来修改类。
    7). 我们可以利用 method_setImplementation 来直接设置某个方法的IMP。
    8). 归根结底,都是偷换了selector的IMP。。

    二、实现

    import <objc/runtime.h>

    @implementation UIViewController (Tracking)

    • (void)load
      {
      static dispatch_once_t onceToken;
      dispatch_once(&onceToken, ^{
      Class class = [self class];
      SEL originalSelector = @selector(viewWillAppear:);
      SEL swizzledSelector = @selector(clq_viewWillAppear:);

          Method originalMethod = class_getInstanceMethod(class, originalSelector);  
          Method swizzledMethod = class_getInstanceMethod(class, swizzledSelector);
          
          // 如果是替换类方法,使用下面
          // Class class = object_getClass((id)self);
          // ...
          // Method originalMethod = class_getClassMethod(class, orginalSelector);
          // Method swizzledMethod = class_getClassMethod(class, swizzledSelctor);
      
          BOOL didAddMethod = 
                  class_addMethod(class,
                             originalSelector,
                              method_getImplementation(swizzledMethod),
                              method_getTypeEncoding(swizzledMethod));
      
           if (didAddMethod) {
               class_replaceMethod(class,
                      swizzledSelector,
                      method_getImplementation(originalMethod),
                      method_getTypeEncoding(originalMethod));       
           } else {
                 method_exchangeImplementations(orgiginalMethod, swizzledMethod);
           }
      

      });
      }

    pragma mark - Method Swizzling

    • (void)clq_viewWillAppear:(BOOL)animated
      {
      [self clq_viewWillAppear:animated];
      }

    三、注意点
    1、object_getclass((id)self)和[self class]的区别
    1)runtime经典图解分析


    Paste_Image.png

    2)源码
    Class object_getClass(id obj)
    {
    if (obj) return obj->getIsa();
    else return Nil;
    }

     + (Class)class {
          return self;
      }
    
      - (Class)class {
         return object_getClass(self);
      }
    
     3)[self class] 指向类对象,类对象存储成员函数,而object_getclass((id)self)指向meta类,meta类指向类方法
    

    2、clq_viewWillAppear实现是否造成递归
    答案是否的,clq_viewWillAppear方法里面调用clq_viewWillApear方法的时候,由于clq_viewWillApear和viewWillApear的实现已交换了,这时候调用clq_viewWillApear的时候,实际上是调用swizzle之前的方法,viewWillApear,所以不会造成递归调用的

    3、不用class_addMethod进行判断,简单用method_exchangeImplementations有什么问题
    由于当要重写的方法(overridden)并没有在目标类中实现(notimplemented),而是在其父类中实现了。这时候用method_exchangeImplementations是达不到目的的,需要在目标类增加一个新的实现方法(override)

    相关文章

      网友评论

          本文标题:Objective-C之Method Swizzle

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