iOS底层原理探索Runtime的基本使用

运行时。OC是运行时机制,也就是在运行的时候的一些机制,其中最主要的是消息机制。
对于C语言,函数的调用在编译的时候会决定调用哪个函数。
而对于OC语言中的函数,属于动态调用过程,在编译的时候并不能决定真正调用哪个函数,只有在真正运行的时候才会根据函数的名称找到对应的函数来调用。

在编译阶段,C语言调用未实现的函数会报错。
在编译阶段,OC可以调用任何函数,即使这个函数并未实现,只要声明过就不会报错。

runtime最主要的有五大作用

发送消息(访问私有函数)
交换方法
动态添加方法
给分类添加属性
字典转模型

1.发送消息(访问私有函数)

方法调用的本质就是让对象发送消息,OC底层实现通过runtime实现发送消息。
最终生成消息机制,是编译器要做的事情。
可以使用clangclang -rewrite-objc main.m 将当前代码进行重新编译,并查看最终生成代码。

NSObject *obj = [NSObject alloc];
obj = [obj init];

最终会转换为

NSObject *obj = ((NSObject *(*)(id, SEL))(void *)objc_msgSend)((id)objc_getClass("NSObject"), sel_registerName("alloc"));
obj = ((NSObject *(*)(id, SEL))(void *)objc_msgSend)((id)obj, sel_registerName("init"));

简化后,可以变为

NSObject *obj = objc_msgSend(objc_getClass("NSObject"), sel_registerName("alloc"));
obj = objc_msgSend(obj, sel_registerName("init"));

其中
objc_msgSend发送消息
objc_getClass获取发送消息的主体
sel_registerName发送消息的编号

当然,我们在使用的时候,不用上面的复杂格式,一般我们可以这样使用:

NSObject *obj = objc_msgSend([NSObject class], @selector(alloc));
obj = objc_msgSend(obj, @selector(init));

使用runtime的基本步骤:

  1. 在文件中引入头文件:#import <objc/message.h>
  2. 将build settings 里面的objc_msgSend修改为NO(xcode6之前苹果可以使用runtime,xcode6之后苹果不推荐使用runtime)

在这里插入图片描述

那,在什么情况下,我们会使用runtime的发送消息机制呢?
一般在,我们需要访问一个私有函数的时候,可以使用runtime

在这里插入图片描述

在这里插入图片描述

方法调用流程:

[person eat];是怎样的一个调用过程?
首先要明白,对象方法列表是在类对象里面。类方法列表是在元类里面。

在person对象中通过isa指针找到person的类对象YZPerson
注册方法编号:sel_registerName(“eat”)
根据方法编号去方法列表里面查找对应的方法
找到方法地址去方法区调用函数的具体实现

在这里插入图片描述

2. 交换方法

交换类方法

在这里插入图片描述

交换对象方法

在这里插入图片描述

交换图

在这里插入图片描述

交换的其实是,方法列表到方法实现。

3. 动态添加方法

在这里插入图片描述

4.给分类添加属性

@property在分类中的作用:只会添加set、get方法的声明,并不会做实现。也不会生成下划线成员属性。

在这里插入图片描述

5. 字典转模型

原文地址:https://www.cnblogs.com/r360/p/15812438.html