在iOS中用Runtime可以做什么?

iOS 常见知识点(一):Runtime:https://www.jianshu.com/p/965bd18cb056
https://www.jianshu.com/p/adf0d566c887
iOS开发-runtime-消息传递和转发机制:http://zhangzr.cn/2018/02/08/iOS%E5%BC%80%E5%8F%91-runtime-%E6%B6%88%E6%81%AF%E4%BC%A0%E9%80%92%E5%92%8C%E8%BD%AC%E5%8F%91%E6%9C%BA%E5%88%B6/

iOS运行时(Runtime)详解+Demo:https://www.jianshu.com/p/adf0d566c887

1.什么是Runtime

  • runtime是运行时,是OC的运行机制,最重要的是消息机制
  • 对于C语言,函数的调用在编译时,就会决定调用哪个函数
  • 对于OC,属于动态调用过程,编译的时候不能决定调用哪个函数,只有在真正运行的时候才会找到对应的函数
  • 在编译的阶段,OC可以调用任何函数,只要声明就不会报错,而C语言未实现的函数编译时就会报错
  • 编译器的工作:把OC代码编译成底层实现,xcode编译器clangclang -rewrite-objc main.m

2.runtime怎么使用

1.先导入头文件

#import <objc/message.h>

2.再调用runtime的方法

//普通方法创建对象p
Person *p = [[Person alloc]init];

//runtime创建对象p
Person *p = objc_msgSend(objc_getClass("Person"),sel_registerName("alloc")); // Person = [p alloc];
p = objc_msgSend(p,sel_registerName("init")); // p = [p init];

//调用不带参数的方法
objc_msgSend(p, @selector(eat) ); //[p eat];

//调用带参数的方法
objc_msgSend(p, @selector(run) , 20); //[p run:20];

3.什么时候用runtime

  • 装逼
  • 可以调用私有的方法,系统的方法
  • 交换方法

4. 方法调用的流程(消息机制)

须知:
对象方法,保存在对应的类的方法列表中
类方法,保存在对应元类的(meta class)方法列表中
[p eat];为例

  1. 寻找p对应的类,即Person类。每个对象都有一个isa指针,指针指向它对应的类,再去类的方法列表中查找对应方法。在[p eat];中,pisa指针指向了Person类(p.isa -> Person)
  2. 注册一个方法编号,sel_registerName("eat")(操作数字比操作字符串快)
  3. 根据方法编号查找对应方法,(在[p eat];中,再去Person类中的方法列表(MethodList)中寻找对应方法)
  4. 根据方法地址去方法区调方法的实现
方法调用流程

5.利用runtime交换方法

需求:改造[UIImage imageNamed:@"1.png"]; 方法,可以检测是否成功加载图片。

方法一:自定义UIImage,重写[UIImage imageNamed:]方法。
  • 弊端:1. 每次使用都需要#import自己的类。2. 项目大了,不好一个个去修改
#import "CYBImage.h"

@implementation CYBImage

+(UIImage *)imageNamed:(NSString *)name{
    UIImage *image = [super imageNamed:name];
    
    if (image){
        NSLog(@"加载成功");
    }else{
        NSLog(@"加载失败");
    }
     
    return image;
}

@end
#import "CYBImage.h"

CYBImage *image = [CYBImage imageNamed:@"1.png"];

//2020-09-25 10:49:30.397798+0800 [54068:2433122] 加载失败
方法二:给UIImage添加分类
  • 弊端:1. 重写系统方法,会覆盖系统的方法 2. 分类中无法调用super

对UIImage添加Category分类,super ——>指向父类(NSObject),父类NSObject中无法使用[ UIImage imageNamed:]这个方法

方法三:使用runtime修改系统的方法

想要修改系统的自带类,只能用runtime解决(交换方法)。

步骤:
  1. 给系统的方法添加分类
  2. 添加一个带有扩展功能的方法
#import "UIImage+image.h"

@implementation UIImage (image)

+(UIImage *)cyb_imageNamed:(NSString *)name{
    //1.加载图片
    UIImage *image = [UIImage imageNamed:name];
    //2.判断加载成功
    if(image) {
        NSLog(@"cyb_imageNamed加载成功");
    }else {
        NSLog(@"cyb_imageNamed加载失败");
    }
    
    return  image;
}
@end
  1. 交换两个方法的实现,只需要交换一次
//把类加载进内存的时候调用,只会调用一次,swift里面没有+load
+(void)load
{
    //获取imageNamed
    //参数1:获取哪个类
    //参数2:获取这个类的哪个方法
    Method imageNamed = class_getClassMethod(self, @selector(imageNamed:));
    //获取cyb_imageNamed
    Method cyb_imageNamed = class_getClassMethod(self, @selector(cyb_imageNamed:));
    //交换方法
    method_exchangeImplementations(imageNamed, cyb_imageNamed);
}
//会调用多次,swift可以用这种方法
+(void)initialize
{
    //dispatch_once可以保证只调用一次
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
         
    });
}
  1. 交换使用到imageNamed:cyb_imageNamed:的地方
+(UIImage *)cyb_imageNamed:(NSString *)name{

    -----------------------这里交换了使用的方法------------------------
    UIImage *image = [UIImage cyb_imageNamed:name];
    -----------------------这里交换了使用的方法------------------------

    if(image) {
        NSLog(@"cyb_imageNamed加载成功");
    }else {
        NSLog(@"cyb_imageNamed加载失败");
    }
    
    return  image;
}
  1. 测试是否交换成功
#import "UIImage+image.h"

UIImage *image = [UIImage imageNamed:@"1.png"];

//2020-09-25 11:16:56.735535+0800 [54357:2444466] cyb_imageNamed加载失败

图解方法交换

方法交换之前
方法交换之后

6. 用Runtime动态添加方法

  • OC都是懒加载机制,只要有一个方法实现了,就会马上添加到方法列表中
  • 当我们调用了一个没有实现的方法,编译时不会报错,但运行时会报错,这时,我们可以让OC动态地在运行时添加方法
[p performSelector: @selector(eat)];

#import <objc/message.h>
//当调用了一个没有实现的方法时,调用这个方法
+(BOOL)resolveInstanceMethod:(SEL)sel{

  if (sel == NSSelectorFromString(@"eat")){
    //class:给哪个类添加方法
    //SEL:添加哪个方法
    //IMP:方法的实现
    //type:方法的类型(v = void ,@ = id , : = SEL)
    class_addMethod(self,sel,(IMP) eat,"v@:");
  }
}

7 动态添加属性

  • 添加属性的本质:让某个属性与某个对象产生关联,即属性的指针指向这个对象。

需求:给NSObject添加属性name。

步骤
  1. 给NSObject添加分类
  2. 在分类中声明属性(分类中添加属性,只会声明set和get方法,不会生成实现,也不会生成下划线的成员属性)
  3. 在分类中添加set和get方法,可以使用全局静态变量(static)来保存属性。
  4. 用runtime添加属性
static NSString* _name;
//给NSObject类添加一个name属性,设置它的set和get方法
-(void)setName:(NSString *)name{
   
   _name = name
  //第一个参数:给哪个类添加属性
  //第二个参数:属性的名称
  //第三个参数:属性值
  //第四个参数:保存策略
  objc_setAssociateObject(self,@"name",name,OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}

-(NSString *)name{
return _name
  //第一个参数:获得哪个类添加属性
  //第二个参数:属性的名称
  return objc_getAssociateObject(self,@"name");
}

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 200,302评论 5 470
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,232评论 2 377
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 147,337评论 0 332
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,977评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,920评论 5 360
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,194评论 1 277
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,638评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,319评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,455评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,379评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,426评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,106评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,696评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,786评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,996评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,467评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,043评论 2 341