zoukankan      html  css  js  c++  java
  • runtime之方法的交换

    工作中没怎么用到runtime的东西,所以一直没怎么看,现在开始拿起来。

    runtime之方法的交换:

    都知道OC中有category可以对已知类进行扩展,但是假如工程中需要修改某类的原方法,若用category的话,调用的时候会调用到category中实现的方法,而原方法中的功能就已经被覆盖,这样就调用不到系统的方法了,为了避免这种情况,我们可以用方法交换的形式:
    如写一个NSURL的分类,现在将它的URLWithString:的方法替换成我们自己写的方法:

    + (void)load{
      static dispatch_once_t onceToken;
      dispatch_once(&onceToken, ^{
        Method urlWithStringMethod = class_getClassMethod(self, @selector(URLWithString:));

        Method wd_urlWithStringMethod = class_getClassMethod(self, @selector(WD_urlWithString:));

        /*交换了URLWithString和WD_urlWithString的函数指针(该指针指向方法的实现),所以交换了之后,若调用URLWithString:方法,实际上是调用了WD_urlWithString方法的实现,而调用了WD_urlWithString:方法,实际上的调用了URLWithString:方法的实现*/


        method_exchangeImplementations(urlWithStringMethod, wd_urlWithStringMethod);
      });
    }

    /*
    在load中将NSURL中的URLWithString方法跟自定义的WD_urlWithString进行了交换
    在外部调用系统的URLWithString:方法,实际上会到WD_urlWithString:中
    */
    + (instancetype)WD_urlWithString:(NSString *)urlString{
      NSURL *url = [NSURL WD_urlWithString:urlString]; //实际调用的URLWithString:方法的实现,所以不会造成无限循环
      if (url == nil) {
        NSLog(@"url is null");
      }
      return url;
    }


    method:

    实际上method是一个结构体,

    struct objc_method {
      SEL method_name OBJC2_UNAVAILABLE;
      char *method_types OBJC2_UNAVAILABLE;
      IMP method_imp OBJC2_UNAVAILABLE;
    }

    method_name 是方法的 selector,可以理解为运行时的方法名;
    *method_types 是一个参数和返回值类型编码的字符串;
    method_imp 是指向方法实现的指针。
    Method Swizzling 的实质是在运行时,访问对象的方法结构体,并改变它的底层实现。

    拿上面的例子来说,变化如下:

    交换前->

    method URLWithString {
      SEL method_name = @selector(URLWithString:)
      char *method_types = “v@:“ //返回值void, 参数id(self),selector(_cmd)
      IMP method_imp = 0x000FFFF //指向([NSURL URLWithString:])
    }
    method WD_urlWithString {
      SEL method_name = @selector(WD_urlWithString:)
      char *method_types = “v@:“ //返回值void, 参数id(self),selector(_cmd)
      IMP method_imp = 0x000EEEE //指向([NSURL WD_urlWithString:])
    }
    交换后->
    method URLWithString {
      SEL method_name = @selector(URLWithString:)
      char *method_types = “v@:“ //返回值void, 参数id(self),selector(_cmd)
      IMP method_imp = 0x000FFFF //指向([NSURL WD_urlWithString:])
    }
    method WD_urlWithString {
      SEL method_name = @selector(WD_urlWithString:)
      char *method_types = “v@:“ //返回值void, 参数id(self),selector(_cmd)
      IMP method_imp = 0x000EEEE //指向([NSURL URLWithString:])
    }
    可以看到使用method_exchangeImplementations实质是交换它们的IMP。
    Method Swizzling,我们可以对系统中的方法进行修改,动态添加。

    在load中处理,因为 +load 方法会在类被添加到 OC 运行时执行,保证了 Swizzling 方法的及时处理。

  • 相关阅读:
    行列式运算法则
    神经元的数学模型
    Neural Network and Artificial Neural Network
    常见的23种设计模式
    Java 基本数据类型 及 == 与 equals 方法的区别
    MySQL经典编程问题
    MyEclipse配置tomcat报错
    MySQL 日期类型函数及使用
    MySQL dump文件导入
    MySQL 的两个特殊属性 unsigned与 zerofill
  • 原文地址:https://www.cnblogs.com/wudan7/p/7422013.html
Copyright © 2011-2022 走看看