Objective-C学习: OC方法调用的本质

张开发
2026/5/4 4:24:50 15 分钟阅读

分享文章

Objective-C学习: OC方法调用的本质
文章目录OC 方法调用的本质是 消息的发送实例对象instance特点四、类对象Class存什么元类对象meta-class存什么SEL 是什么本质IMP 是什么Method 是什么完整调用流程一、从一行代码开始所有一切的起点二、Step 0selector table方法名 → SEL三、Step 1变成消息发送四、Step 2找到类isa五、Step 3先查 cache最快)六、Step 4查 method list真正数据源七、Step 5查父类继承链八、Step 6还找不到 → runtime 动态流程你刚刚那张图① 动态方法解析② 快速转发③ 完整消息转发④ 还不行 → 崩溃九、Step 7最终执行 IMP本质OC 方法调用的本质是 消息的发送OC 中对象本身只存储实例变量, (成员变量) 和 一个isa指针, 不存方法, 方法都存储在类对象中实例对象instanceinstance ├── isa → Class └── ivars成员变量特点存储数据属性、本质是 ivarivarinstance variable是实例变量用于在对象中存储数据是属性property的底层实现。property ivar getter/setter 方法不存方法每个对象一份Person *p [[Person alloc] init];四、类对象ClassClass ├── isa → meta-class ├── superclass → 父类 ├── cache方法缓存 ├── method list实例方法 └── ivar list成员变量信息存什么实例方法-方法属性信息协议等所有实例共享同一个 Class元类对象meta-classmeta-class ├── isa → 根元类 ├── superclass → 父类的 meta-class ├── cache └── method list类方法存什么类方法 方法 (void)test;和类对象一样, 一个类对象只有一个元类对象SEL 是什么SEL sel selector(test);本质SEL是一个方法名的唯一标识类似 key底层是一个字符串但做了唯一化相同方法名 → 同一个 SELselector(test)本质类似test但 runtime 会优化成唯一 ID提高查找效率IMP 是什么typedef id (*IMP)(id, SEL, ...);本质函数指针指向方法真正的实现代码是最终被 CPU 执行的东西Method 是什么运行时里还有一个结构struct method_t { SEL name; // 方法名 IMP imp; // 方法实现 };可以理解为一张表SEL方法名IMP函数地址test0x123456完整调用流程Objective-C 的方法调用本质是 runtime 通过isa找到类利用SEL在cache → method list → 父类链中查找对应的IMP命中后执行函数若未找到则进入动态方法解析与消息转发流程。一、从一行代码开始所有一切的起点[obj run];编译器会做两件事二、Step 0selector table方法名 → SELselector(run)会被注册到一张全局表selector tablerun → SEL(0x1111)同一个方法名 → 永远同一个 SEL本质把字符串变成唯一指针加速比较三、Step 1变成消息发送objc_msgSend(obj, SEL)OC 没有“直接调用方法”全是发消息四、Step 2找到类isaobj → isa → Class对象只存ivar数据isa指向类方法都在类里五、Step 3先查 cache最快)Class.cache SEL → IMP如果有run → 0x123456直接执行 IMP结束六、Step 4查 method list真正数据源Class.method list SEL → IMP 本质结构struct method_t { SEL name; IMP imp; };找到后拿到 IMP写入 cache优化七、Step 5查父类继承链Class → superclass → superclass → ...每一层都cache → method list八、Step 6还找不到 → runtime 动态流程你刚刚那张图① 动态方法解析 (BOOL)resolveInstanceMethod:(SEL)sel你可以动态加方法IMP② 快速转发- (id)forwardingTargetForSelector:(SEL)aSelector;换对象处理return otherObj;③ 完整消息转发- methodSignatureForSelector - forwardInvocation你自己完全接管调用④ 还不行 → 崩溃unrecognized selector sent to instance九、Step 7最终执行 IMP本质imp(obj, SEL); IMP 本质是函数指针void run(id self, SEL _cmd) { // 方法实现 }

更多文章