消息的解释
在其他语言里面,我们可以用一个类去调用某个方法,在OC里面,这个方法就是消息。某个类调用一个方法就是向这个类发送一条消息。举个例子:
Person *p1 = [[Person alloc] init];
Person *p2 = [[Person alloc] init];
[p1 beFriendWith:p2];
我们有个Person的类,p1这个实例发送了一条beFriendWith:
的消息。你也许还看过这种调用方式:
[p1 performSelector:@selector(beFriendWith:) withObject:p2];
其目和上面的一样,都是向p1发送了一条beFriendWith:
的消息,传人的参数都是p2。
这里简单介绍一下SEL
和IMP
:
-
SEL
: 类成员方法的指针,但和C的函数指针还不一样,函数指针直接保存了方法的地址,但是SEL
只是方法编号。 -
IMP
: 函数指针,保存了方法地址。
我们叫@selector(beFriendWith:)
为消息的选择子或者选择器。(A selector identifying the message to send)
消息转发机制
先会调用objc_msgSend
方法,首先在 Class 中的缓存查找IMP
,没有缓存则初始化缓存。如果没有找到,则向父类的 Class 查找。如果一直查找到根类仍旧没有实现,则执行消息转发。
1. Method resolution 方法解析处理阶段
- 调用
resolveInstanceMethod:
方法,允许用户在此时为该 Class 动态添加实现。如果有实现了,则调用并返回。如果仍没实现,继续下面的动作。
2. Fast forwarding 快速转发阶段 (后面阶段都针对对象来处理,不考虑类方法)
- 调用
forwardingTargetForSelector:
方法,尝试找到一个能响应该消息的对象。如果获取到,则直接转发给它。如果返回了nil
,继续下面的动作。
3. Normal forwarding 常规转发阶段
- 调用
methodSignatureForSelector:
方法,尝试获得一个方法签名。如果获取不到,则直接调用doesNotRecognizeSelector
抛出异常。 - 调用
forwardInvocation:
方法,将上一步获取到的方法签名包装成Invocation
传入,如何处理就在这里面了。
如果直接调用_objc_msgForward
函数则会直接进入消息转发。
网友评论