runtime 是 oc 语音的基础
首先runtime的核心机制是消息机制 也就是oc的消息机制
首先oc的消息机制可以分为五部分
1 动态语言
2 实例对象 类对象 元类对象之间的关系
3 实例对象instance调用对象方法的过程链
4 类对象调用类方法的过程链
5 runtime objc_msgSend 函数 具体解析
1 动态语言这块
首先 从源代码到程序运行一般分为三个阶段 编译阶段 链接阶段 运行阶段
oc 是动态 动态语音在编译阶段 链接阶段 不知道变量的数据类型 也不知道具体真正实现的那个方法 只有在运行时才会去检查 变量的数据类型 和 根据 方法名查找对应的方法进行实现 这样oc就可以把一些重要的工作从编译阶段 链接阶段 转移到运行阶段 这样就使o c具备更好的灵动性 而实现的的基础就是runtime
而 在编译阶段 链接阶段 只需要进行 代码语法检验 还有就是生成运行时可执行的文件就可以了
2 实例对象 类对象 元类对象之间的关系
实例对象的isa指针指向类对象,类对象的isa指针指向元类对象,元类对象的isa指针指向基类元类对象。因为OC中类实质是一个结构体,除了isa指针,还包含superclass指针(实质都是NSObject的对象),还包含属性方法表等。类是对数据以及方法的封装,所以这三者的关系链也就由isa指针链接起来了。
另外还有就是 类的成员变量 实例方法 归属实例对象 类的类方法归属在原类中 归属该类对象
struct objc_class {
Class _Nonnull isa; // 指向所属类的指针(_Nonnull)
Class _Nullable super_class; // 父类
const char * _Nonnull name; // 类名(_Nonnull)
long version; // 类的版本信息(默认为0)
long info; // 类信息(供运行期使用的一些位标识)
long instance_size; // 该类的实例变量大小
struct objc_ivar_list * _Nullable ivars; // 该类的成员变量链表
struct objc_method_list * _Nullable * _Nullable methodLists; // 方法定义的链表
struct objc_cache * _Nonnull cache; // 方法缓存
struct objc_protocol_list * _Nullable protocols; // 协议链表
} ;
3 实例对象instance调用对象方法的过程链
通过实例对象instance的isa指针找到类对象class,找到即调用
如果找不到,通过实例对象的instance中的superclass找到父类对象,通过父类对象的isa指针找到父类对象的类对象class,找到调用方法
如果仍然找不到,那么系统会通过消息转发机制进行消息转发,走消息转发的响应链,最后如果都没有能够处理消息的方法的话,那么会抛出unselector 的异常
4 类对象调用类方法的过程链
通过类对象class isa指针找到元类对象meta-class,通过存储在元类对象的方法表查找对应的方法进行调用
如果没有找到,那么通过class的superclass 指针找到父类superclass,然后通过父类的superclass的isa指针找到父类的元类对象super-meta-class,通过存储在父类的元类对象meta-class找到类对象进行调用。
5 runtime在其中具体的函数及其作用
Objective-C 语言 中,对象方法调用都是类似 [receiver selector]; 的形式,其本质就是让对象在运行时发送消息的过程。
我们来看看方法调用 [receiver selector]; 在『编译阶段』和『运行阶段』分别做了什么?
编译阶段:[receiver selector]; 方法被编译器转换为:
objc_msgSend(receiver,selector) (不带参数)
objc_msgSend(recevier,selector,org1,org2,…)(带参数)
运行时阶段:消息接受者 recevier 寻找对应的 selector。
通过 recevier 的 isa 指针 找到 recevier 的 Class(类);
在 Class(类) 的 cache(方法缓存) 的散列表中寻找对应的 IMP(方法实现);
如果在 cache(方法缓存) 中没有找到对应的 IMP(方法实现) 的话,就继续在 Class(类) 的 method list(方法列表) 中找对应的 selector,如果找到,填充到 cache(方法缓存) 中,并返回 selector;
如果在 Class(类) 中没有找到这个 selector,就继续在它的 superClass(父类)中寻找;
一旦找到对应的 selector,直接执行 recevier 对应 selector 方法实现的 IMP(方法实现)。
若找不到对应的 selector,消息被转发或者临时向 recevier 添加这个 selector 对应的实现方法,否则就会发生崩溃。
在上述过程中涉及了好几个新的概念:objc_msgSend、isa 指针、Class(类)、IMP(方法实现) 等,下面我们来具体讲解一下各个概念的含义。