iOS_Runtime2_方法交换

  • 利用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

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值