Objective-C 的消息转发
消息在OC中方法调用是一个消息发送的过程。OC方法最终被生成为C函数,并带有一些额外的参数(self 、_cmd)
objc_msgSend(void /* id self, SEL op, ... */ )
OC的方法本质
- 在编译时你写的 OC 函数调用的语法都会被翻译成一个 C 的函数调用 objc_msgSend()
[array insertObject:obj atIndex:5];
//等价于
objc_msgSend(array, @selector(insertObject:atIndex:), obj, 5);
OC消息转发的步骤
1.通过 的 指针 找到 的 ;
2.在 的 (方法缓存) 的散列表中寻找对应的(方法实现);
3.如果在(方法缓存) 中没有找到对应的 (方法实现) 的话,就继续在 的 (方法列表) 中找对应的 ,如果找到,填充到 (方法缓存) 中,并返回 ;
4.如果在 中没有找到这个 ,就继续在它的 (父类)中寻找;
5.一旦找到对应的 ,直接执行 对应 方法实现的 (方法实现)。
6.若找不到对应的 ,要开始进入 ,消息被转发或者临时向 添加这个 对应的实现方法,否则就会发生崩溃。
+ (BOOL)resolveInstanceMethod:(SEL)sel;
+ (BOOL)resolveClassMethod:(SEL)sel;
- (id)forwardingTargetForSelector:(SEL)aSelector;
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector;
- (void)forwardInvocation:(NSInvocation *)anInvocation;
-
动态方法解析和消息转发流程:
图片来自网络
OC 中给一个对象发送消息的完整步骤:
1.在对象类的 dispatch_table 中尝试找到该消息。如果找到了,跳到相应的函数IMP去执行实现代码(参考OC消息转发的步骤);
2.如果没有找到,运行时系统会发送+resolveInstanceMethod:或者 +resolveClassMethod:尝试去 resolve 这个消息;
3.如果 resolve 方法返回NO,运行时系统就发送 -forwardingTargetForSelector: 允许你把这个消息转发给另一个对象;(resolve 方法返回YES时,运行时系统就会重新启动一次消息发送的过程)
4.如果没有新的目标对象返回,运行时系统就会调用 -methodSignatureForSelector:和-forwardInvocation: 消息。你可以发送-invokeWithTarget:消息来手动转发消息或者发送 -doesNotRecognizeSelector:抛出异常;
5.如果都没有,系统抛出异常。
类方法的调用过程 和对象方法调用差不多,流程如下:
1.通过类对象指针 找到所属的 (元类);
2.在 (元类) 的(方法列表) 中找到对应的 ;
执行对应的 。
注意
需要注意的是类方法的解析,动态增加方法时候,需要加到元类上,因为类方法列表是在元类对象中存储的。