Objective-C Runtime 核心概念详解

6 阅读2分钟

SEL、IMP、cache、“v@:”、_cmd

如果说 objc_msgSend 是 Objective-C Runtime 的发动机,

那么下面这五个概念,就是发动机里最关键的零部件。

本文将围绕它们,回答三个核心问题:

  1. 它到底是什么?
  2. Runtime 在什么时候、为什么要用它?

一、SEL —— 消息的名字,而不是方法

1. SEL 是什么

typedef struct objc_selector *SEL;
  • SEL 不是字符串
  • 是一个 全局唯一的 Selector 标识
  • 相同的方法名,在进程内只有一个 SEL
@selector(foo) == sel_registerName("foo"); // YES

SEL 只表示“要发什么消息”,不表示“怎么实现”。


2. SEL 在 Runtime 中的作用

在消息发送时:

objc_msgSend(obj, sel);

Runtime 使用 SEL:

  • 在 cache 中查找 IMP

  • 在 method list 中匹配方法

  • 在转发阶段判断消息类型

整个 Runtime 流程,都是围绕 SEL 的查找与匹配 展开的。


二、IMP —— 真正被执行的函数

1. IMP 是什么

typedef id (*IMP)(id self, SEL _cmd, ...);
  • IMP 本质是一个 C 函数指针

  • 指向方法的真实实现地址

  • 找到 IMP,Runtime 的任务就结束了

Objective-C 的“动态”,到 IMP 为止。


2. IMP 在 Runtime 中的作用

当 cache 命中时:

imp(self, _cmd);

此时:

  • 不再有方法查找

  • 不再有消息机制

  • 只剩一次普通的 C 函数调用

这也是为什么:

cache 命中后,方法调用速度接近 C 函数。


三、cache —— 方法调用的高速缓存

1. cache 是什么

  • cache 是一个 SEL → IMP 的哈希表
  • 位于 Class 结构体中
  • 用于加速方法调用
Class
 ├─ cache
 ├─ method list
 └─ superclass

2. cache 在 Runtime 中的作用

objc_msgSend 的查找顺序:

cache → method list → superclass
  • 绝大多数方法调用只走 cache

  • method list 和 superclass 查找是慢路径

cache 是 Runtime 性能的生命线。


四、“v@:” —— 方法类型编码(Type Encoding)

1. “v@:” 是什么

v   返回值 void
@   selfid)
:   _cmd(SEL)

表示方法签名:

- (void)foo;

等价于 C 函数:

void foo(id self, SEL _cmd);

2. Type Encoding 在 Runtime 中的作用

  • 描述 IMP 的真实参数布局

  • NSInvocation / 消息转发严重依赖它

  • Runtime 不会自动校验是否匹配

Runtime 相信你是对的。


五、_cmd —— 当前正在执行的方法名

1. _cmd 是什么

  • _cmd 是一个隐藏参数
  • 表示当前方法的 SEL
- (void)foo {
    _cmd == @selector(foo); // YES
}

2. _cmd 在 Runtime 中的作用

  • Runtime 自动传入
  • 用于日志、AOP、转发识别
NSLog(@"当前方法:%@", NSStringFromSelector(_cmd));

六、五者之间的关系(一定要理解)

SEL  —— 决定“调用哪个方法”
cache—— 决定“能否快速找到”
IMP  —— 决定“执行哪段代码”
"v@:" —— 决定“如何正确调用”
_cmd —— 决定“当前正在执行谁”

它们共同组成了 Objective-C 的方法调用体系。


七、总结一句话版本

SEL 是钥匙,IMP 是门,cache 是高速路,

“v@:” 是地图,_cmd 是门牌号。

理解它们,

你就真正站在了 Objective-C Runtime 的入口处