iOS_Runtime2_方法交换

来源:互联网 发布:人工智能就业 知乎 编辑:程序博客网 时间:2024/06/04 19:25
  • 利用Runtime实现的方法交换,主要是为了修改系统的方法实现。
  • Objective-C 提供了一下API用于动态替换类方法或者实例方法的实现:
    class_replaceMethod 替换类方法的定义
    method_exchangeImplementations 交换两个方法的实现
    method_setImplementation 设置一个方法的实现
    注:class_replaceMethod 试图替换一个不存在的方法时候,会调用class_addMethod为该类增加一个新方法

以UIImage类目为例,实现类方法,以及对象方法的实现交换。
代码示例如下:

// UIImage+Image.h@interface UIImage (Image)// 对象方法- (void)sayOne;- (void)sayTwo;@end// UIImage+Image.m#import <objc/message.h>@implementation UIImage (Image)+ (void)load{    // 修改类方法实现示例:    Method imageNamedMethod = class_getClassMethod(self, @selector(imageNamed:));    Method xmg_imageNamedMethod = class_getClassMethod(self, @selector(xmg_imageNamed:));    // 利用runtime实现方法的交换    method_exchangeImplementations(imageNamedMethod, xmg_imageNamedMethod);    // 修改对象方法实现示例:    Method method1 = class_getInstanceMethod(self, @selector(sayOne));    Method method2 = class_getInstanceMethod(self, @selector(sayTwo));    method_exchangeImplementations(method1, method2);}+ (UIImage *)xmg_imageNamed:(NSString *)name{    // 由于已经实现了方法交换,故[UIImage xmg_imageNamed:name]的内部调用实际上走的是[UIImage imageNamed:name]原本的内部实现。    UIImage *image = [UIImage xmg_imageNamed:name];    if (image) {        NSLog(@"加载成功");    } else {        NSLog(@"加载失败");    }    return image;}- (void)sayOne{    NSLog(@"One");}- (void)sayTwo{    NSLog(@"Two");}@end// 调用示例:#import "UIImage+Image.h" // 导入此类目UIImage *image = [[UIImage alloc]init];[image sayOne]; //输出:Two[UIImage imageNamed:@"one.png"]; //输出:加载成功

总结:

  1. Method class_getInstanceMethod(Class cls, SEL name)获取类方法。参数一Class cls:获取哪个类的方法;参数二SEL name:获取类的哪个方法;返回值类型为Method
  2. Method class_getInstanceMethod(Class cls, SEL name)获取对象方法。参数一Class cls:获取哪个类的方法;参数二SEL name:获取类的哪个对象方法;返回值类型为Method
  3. void method_exchangeImplementations(Method m1, Method m2)替换方法m1与方法m2的实现。
  4. 在类目中,最好不要重写系统方法。一旦重写,将会把系统方法实现给干掉,因为分类不是继承父类,而是继承NSObject,因此super不是改类的方法,而是直接覆盖掉了父类的行为。
  5. + (void)load+ (void)initialize的区别:
    • + (void)load:当类加载进内存的时候调用,而且不管有没有子类,都只会调用一次,在main函数之前调用。
    • 用途:(1)可以新建类在该类中实现一些配置信息。(2)runtime交换方法的时候,因为只需要交换一次方法,所有可以在该方法中实现交换方法的代码,用于只实现一次的代码 。
    • + (void)initialize:当类被初始化的时候调用,可能会被调用多次,若是没有子类,则只会调用一次,若是有子类的话,该方法会被调用多次,若是子类的继承关系,先会调用父类的+ (void)initialize方法,然后再去调用子类的+ (void)initialize方法(若是继承关系,调用某个方法的时候,先会去父类中查找,若是父类中没有方法的实现就去子类中查找)
    • 用途:(1)在设置导航栏的全局背景的时候,只需要设置一次,可以重写该方法设置,最好是在该方法判断子类,若是自己,则实现设置全局导航栏的方法,若不是自己则跳过实现。(2)在创建数据库代码的时候,可以在该方法中去创建,保证只初始化一次数据库实例,也可以用dispatch或是懒加载的方法中初始化数据库实例,也能保证只初始化一次数据库实例。其中也可以在+ (void)initialize方法中用dispatch也能保证即使有子类也只会初始化一次。

iOS_Runtime1_消息发送机制

iOS_Runtime3_动态添加方法

iOS_Runtime4_动态添加属性

iOS_Runtime5_消息转发

iOS_Runtime6_字典转化为模型应用


代码地址:
https://github.com/FlyingKuiKui/RunTime.git

原创粉丝点击