Runtime 是 Objective-C 的灵魂,它是一套用 C + 汇编 实现的运行时库,把 OC 大量语法特性从编译期推迟到运行期处理,让 OC 成为真正的动态语言。
简单说:OC 不关心 “调用哪个函数”,只关心 “发送什么消息”,真正的方法查找、执行、转发全部在运行时决定。
例如:[obj doSomething]编译期不会生成直接函数调用,而是转为:objc_msgSend(obj, @selector(doSomething))真正的实现查找与执行,完全在运行时完成。
一、类与对象的底层本质(Runtime 世界观)
Runtime 中一切皆为结构体,对象、类、元类没有神秘之处。
1. 对象(instance / 实例对象)
- 本质:
typedef struct objc_object *id - 核心:包含一个 isa 指针,指向自己的类对象(Class)
- 作用:存储成员变量值
2. 类对象(Class)
-
本质:
typedef struct objc_class *Class -
存储:实例方法、属性、成员变量、协议、父类指针
-
成员:
super_class:父类name:类名ivars:成员变量methodLists:实例方法(- 方法)cache:方法缓存(加速调用)protocols:协议
3. 元类(Meta Class)
- 元类 = 类对象的类
- 存储:类方法(+ 方法)
- 继承链:元类也遵循继承
- 闭环:根元类的 isa 指向自己,super_class 指向根类(NSObject)
一句话总结:
- 实例对象 isa → 类对象
- 类对象 isa → 元类对象
- 元类对象 isa → 根元类
- 根元类 isa → 自己
二、消息机制:OC 方法调用的真相
OC 没有 “函数调用”,只有消息发送(Message Passing) 。
消息发送完整流程(objc_msgSend)
- 查缓存 cache_t从 isa 找到类 → 优先查方法缓存缓存使用哈希表,命中极快,是 Runtime 高性能核心。
- 查当前类方法列表找到 → 执行 IMP → 加入缓存未找到 → 继续
- 沿继承链向上查找(父类 → 根类)重复:缓存 → 方法列表仍未找到 → 进入消息转发流程
三、消息转发(三次补救机会)
方法找不到时,Runtime 不会立刻崩溃,而是给 3 次补救机会。
第一道:动态方法决议
+resolveInstanceMethod: / +resolveClassMethod:
- 机会:动态添加方法实现
- 用途:懒加载方法、动态生成实现
第二道:快速转发
-forwardingTargetForSelector:
- 机会:返回一个备用接收者
- 用途:轻量级多重继承、组件解耦
- 优点:速度快、无开销
第三道:完整消息转发
-methodSignatureForSelector:返回方法签名-forwardInvocation:处理 NSInvocation
- 可修改:目标、selector、参数、返回值
- 可转发给多个对象
- 最灵活,性能最低
最终崩溃
doesNotRecognizeSelector:未处理 → 抛出 unrecognized selector 异常
四、Method Swizzling(方法调配)
Runtime 最强大、最常用的动态技术,是 AOP 面向切面编程的基石。
核心原理
- SEL:方法编号(名字)
- IMP:函数指针(实现)
- Runtime 本质是:SEL 与 IMP 的映射表
交换两个方法的 IMP,即可实现 “调用 A 方法,执行 B 逻辑”。
核心 API
method_exchangeImplementations(Method1, Method2)
最佳实践
- 在
+load中执行 - 必须用
dispatch_once保证只交换一次 - 不要直接替换系统方法,应使用 “自定义方法包裹原方法”
- 避免滥用、避免冲突
典型用途
- 全局无痕埋点
- 页面统计 / 点击统计
- 系统控件功能增强
- 防崩溃(数组、字典保护)
- KVO、weak 底层基于类似原理
五、Runtime 四大动态能力(面试高频)
1. 动态创建类
objc_allocateClassPair``class_addIvar / class_addMethod``objc_registerClassPair可在运行时凭空生成类,常用于:
- ORM 映射
- 动态代理
- KVO 底层(KVO 会动态生成子类)
2. 动态遍历成员变量 & 属性
class_copyIvarList``class_copyPropertyList
用途:
- JSON -> Model 自动转换(MJExtension、YYModel)
- 字典转模型
- 自动化归档解档
3. 关联对象(Category 添加属性)
分类不能直接添加属性,因为不生成 ivar。解决方案:objc_setAssociatedObject``objc_getAssociatedObject
作用:动态绑定对象到某个实例,实现分类 “伪属性”。
4. 动态方法调用与消息转发
完全在运行时决定方法调用,支持热修复、动态路由、组件化通信。
六、Runtime 的真正意义(总结)
Runtime 让 OC 拥有:
- 动态类型(运行时才确定对象类型)
- 动态方法(运行时才查找实现)
- 动态转发(找不到可补救)
- 动态修改(交换方法、增删属性、创建类)
它是以下技术的底层基石:
- KVO / KVC
- weak 自动置空
- Category
- 消息转发
- AOP
- 热修复
- JSON 转模型
- 组件化 & 路由
理解 Runtime,你就真正理解了 iOS 的底层运行逻辑。
总结(极简记忆版)
- Runtime = OC 的灵魂,用 C + 汇编实现
- 方法调用 = 消息发送,不是函数调用
- 对象 → 类 → 元类 → 根元类(闭环)
- 查找流程:缓存 → 本类 → 父类 → 转发 → 崩溃
- Method Swizzling = 交换 SEL ↔ IMP 映射
- 动态能力:创建类、遍历属性、关联对象、消息转发