iOS runtime消息转发

消息的解释

在其他语言里面,我们可以用一个类去调用某个方法,在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。

这里简单介绍一下SELIMP

  • 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函数则会直接进入消息转发。

你可能感兴趣的:(iOS runtime消息转发)