1. Runtime 架构详解与内部工作机制
OC 作为一门动态语言,其强大的灵活性主要源于其底层运行时系统(Runtime)。Runtime 系统实质上是一套 C 和汇编语言编写的 API,它作为 OC 与底层系统之间的桥梁,使得 OC 拥有了动态特性。
OC Runtime 系统的核心架构由以下几个关键组件构成:
- Class 结构体:用于表示类的基本单元
- Object 结构体:表示对象实例
- Method 结构体:封装方法信息
- IMP 函数指针:指向方法的实际实现
- SEL 选择器:方法的唯一标识符
在 iOS 开发中,我们日常编写的 OC 代码最终都会转换为 Runtime 的 C 函数调用。这一转换过程由编译器和运行时系统共同完成。

现在,让我们来看一下 Runtime 系统中最核心的几个数据结构的定义:
// objc 对象结构
struct objc_object {
Class isa; // 指向类的指针
};
// 类结构
struct objc_class {
Class isa; // 元类指针
Class super_class; // 父类指针
const char *name; // 类名
long version; // 版本信息
long info; // 类信息
long instance_size; // 实例大小
struct objc_ivar_list *ivars; // 实例变量列表
struct objc_method_list **methodLists; // 方法列表
struct objc_cache *cache; // 方法缓存
struct objc_protocol_list *protocols; // 协议列表
};
// 方法结构
struct objc_method {
SEL method_name; // 方法选择器
char *method_types; // 方法类型编码
IMP method_imp; // 方法实现函数指针
};
Runtime 系统的核心工作原理围绕着这些结构体展开,通过它们实现了 OC 语言的动态特性,包括动态类型、动态绑定以及动态加载等功能。
2. 消息传递机制
2.1 objc_msgSend实现原理
OC 中的方法调用本质上是消息传递过程。当我们编写如下代码时:
[object method:argument];
编译器会将其转换为:
objc_msgSend(object, @selector(method:), argument);
objc_msgSend 函数是 Runtime 系统的核心,它的基本实现原理如下:
- 获取对象的
isa指针,找到对应的类 - 在类的方法缓存中查找方法
- 如果缓存中找不到,则在方法列表中查找
- 如果当前类中找不到,则沿着继承链向上查找
- 如果继承链上都没有找到,则进入消息转发流程
- 找到方法后,执行对应的 IMP 函数指针
objc_msgSend 主要使用汇编语言实现,以保证最高的性能。其伪代码逻辑大致如下:
id objc_msgSend(id self, SEL _cmd, ...) {
if (self == nil) return nil;
// 查找实现
IMP imp = lookUpImpOrForward(self, _cmd);
// 执行方法实现,传递所有参数
return imp(self, _cmd, ...);
}
2.2 方法查找流程分析
当 objc_msgSend 函数开始查找方法实现时,会按照以下顺序执行查找:

- 缓存查找:首先在对象所属类的方法缓存(cache)中查找,缓存使用哈希表实现,查找速度非常快。
- 当前类查找:如果缓存中没有找到,则在类的方法列表(methodLists)中查找。这个过程相对较慢,因为需要遍历方法列表。
- 父类链查找:如果在当前类中没有找到方法,则沿着继承链向上查找父类的方法,同样遵循缓存优先的原则。
- 动态解析:如果继承链上都没有找到对应方法,则会触发动态方法解析流程,调用
+resolveInstanceMethod:或+resolveClassMethod:方法。 - 消息转发:如果动态解析未能解决问题,则进入完整的消息转发流程。
方法查找的源码实现位于 objc-runtime-new.mm 文件中的 lookUpImpOrForward 函数:
IMP lookUpImpOrForward(id obj, SEL sel, Class cls, int behavior) {
// 缓存查找
if (cache_getI

最低0.47元/天 解锁文章
1万+

被折叠的 条评论
为什么被折叠?



