Objective-C(OC)的消息机制是其最核心、最具特色的运行时特性之一。与 C++ 或 Java 等语言在编译期绑定方法调用不同,OC 的方法调用是在运行时动态解析的,这种机制称为 消息传递(Message Passing)。
一、什么是消息机制?
在 OC 中,调用一个方法实际上是在向对象发送一条消息。例如:
[receiver doSomething];
这行代码在编译时不会直接生成函数调用指令,而是被转换为对运行时函数 objc_msgSend 的调用:
objc_msgSend(receiver, @selector(doSomething));
✅ 关键点:方法调用 = 发送消息 → 运行时动态查找实现(IMP)
二、消息发送的完整流程
当向一个对象发送消息时,Runtime 会按以下顺序处理:
1. 快速查找(Fast Path)
通过
receiver->isa获取类。在该类的 方法缓存(cache_t) 中查找
SEL(方法名)对应的实现(IMP)。如果命中缓存(常见于频繁调用的方法),直接跳转执行,效率极高。
2. 慢速查找(Slow Path)
如果缓存未命中:
遍历当前类的 方法列表(method list)。
若未找到,则通过
class->superclass沿着继承链向上查找(父类 → 祖父类 → … → NSObject)。找到后,将方法加入缓存,再调用。
3. 动态方法解析(Dynamic Method Resolution)
如果继承链中都找不到该方法:
Runtime 会调用
+resolveInstanceMethod:(实例方法)或+resolveClassMethod:(类方法)。开发者可在此阶段动态添加方法实现(使用
class_addMethod)。
+ (bool)resolveInstanceMethod:(SEL)sel {
if (sel == @selector(dynamicMethod:)) {
class_addMethod(self, sel, (IMP)dynamicImplementation, "v@:@");
return YES;
}
return [super resolveInstanceMethod:sel];
}
4. 消息转发(Message Forwarding)
如果仍无法解析,则进入转发阶段,分两步:
a. 备援接收者(Fast Forwarding)
调用
-forwardingTargetForSelector:可返回另一个能响应该消息的对象,Runtime 会直接将消息转发给它。
优点:开销小,不创建
NSInvocation。
- (id)forwardingTargetForSelector:(SEL)aSelector {
if (aSelector == @selector(specialMethod)) {
return self.helperObject; // 由 helper 处理
}
return [super forwardingTargetForSelector:aSelector];
}
b. 完整消息转发(Full Forwarding)
如果上一步返回 nil,则:
调用
-methodSignatureForSelector:获取方法签名(必须实现,否则 crash)。创建
NSInvocation对象,封装 target、selector、参数。调用
-forwardInvocation:,开发者可自定义处理逻辑(如记录日志、网络调用等)。
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector {
if (/* 可处理 */) {
return [NSMethodSignature signatureWithObjCTypes:"v@:@"];
}
return [super methodSignatureForSelector:aSelector];
}
- (void)forwardInvocation:(NSInvocation *)anInvocation {
SEL sel = [anInvocation selector];
if ([self.helper respondsToSelector:sel]) {
[anInvocation invokeWithTarget:self.helper];
} else {
[super forwardInvocation:anInvocation];
}
}
⚠️ 如果以上所有步骤都失败,程序会抛出 unrecognized selector sent to instance 异常并 crash。
三、消息机制的核心数据结构
四、消息机制的优势与代价
✅ 优势
高度动态性:支持运行时添加/替换方法(Method Swizzling)、KVO、Core Data 等。
灵活转发:可实现代理、消息代理、远程调用等高级模式。
解耦设计:发送者无需知道接收者是否能响应消息。
❌ 代价
性能开销:相比静态调用,消息发送有查找、缓存、可能的转发开销。
安全性降低:编译器无法检查方法是否存在(需依赖 Clang 警告或静态分析)。
💡 优化:现代 Runtime 使用 缓存(bucket hash table) 和 tagged pointer / inline cache 技术,使消息发送速度接近虚函数调用。
五、常见应用场景
KVO(Key-Value Observing):通过 isa-swizzling 动态生成子类并重写 setter。
Method Swizzling:交换方法实现,用于埋点、日志、修复 bug。
响应式编程(如 ReactiveCocoa):利用消息转发实现信号链。
JSON 模型转换:通过
setValue:forKey:利用 KVC(基于消息机制)自动赋值。
六、总结
OC 的消息机制 = 动态绑定 + 缓存优化 + 失败容错(解析/转发)
流程图简化如下:
[receiver message]
↓
objc_msgSend(receiver, SEL)
↓
1. 查缓存 → 命中?→ 执行 IMP
↓ 否
2. 查方法列表 → 找到?→ 缓存 + 执行
↓ 否
3. 沿 superclass 链向上查找
↓ 未找到
4. +resolveInstanceMethod:
↓ 未解决
5. -forwardingTargetForSelector:
↓ 返回 nil
6. -methodSignatureForSelector: → 创建 NSInvocation
↓
7. -forwardInvocation:
↓ 仍失败
8. unrecognized selector exception → crash
理解消息机制,是掌握 Objective-C 高级特性和调试疑难问题的关键。