Objective-C的消息转发过程

实例方法(实例方法)消息转发的顺序如下:

1、检查忽略的Selector,比如当我们运行在有垃圾回收机制的环境中,将会忽略retain和release消息。

2、检查receiver是否为nil。不像其他语言,nil在objective-C中是完全合法的,并且这里有很多原因你也愿意这样,比如,至少我们省去了给一个对象发送消息前检查对象是否为空的操作。如果receiver为空,则会将 selector也设置为空,并且直接返回到消息调用的地方。如果对象非空,就继续下一步。

3、接下来会根据SEL到当前类中查找对应的IMP,首先会在cache中检索它,如果找到了就根据函数指针跳转到这个函数执行,否则进行下一步。

4、检索当前类对象中的方法表(method list),如果找到了,加入cache中,并且就跳转到这个函数之行,否则进行下一步。

5、从父类中寻找,直到根类:NSObject类。找到了就将方法加入对应类的cache表中,如果仍为找到,则要进入动态方法决议,也就是说,如果你在父类中实现了这个方法,也是不会开启动态方法决议机制的,动态方法决议机制是在程序中没有这个selector的情况下才运作的。

6.动态方法决议过程

6.1.动态方法解析(resolveInstanceMethod:),调用时机为当被调用的方法实现部分没有找到,而消息转发机制启动之前的这个中间时刻,这之后将会开启消息转发机制。

6.2.当动态方法解析发现无法找到方法之后,会启动消息转发机制。首先消息会发送到 本类的 forwardingTargetForSelector: 方法中,如果没有做任何处理默认情况下则是按照继承关系向父类直到根类转发消息。

6.3.如果直到根类仍未发现进行任何处理,则会调用 methodSignatureForSelector: 方法,如果没有实现则会按照继承关系向父类直到根类查询方法签名。

6.4.如果在 methodSignatureForSelector: 方法中进行了处理,则会调用 forwardInvocation: 方法进行最后的处理,该方法的默认实现是发送 doesNotRecognizeSelector: 消息,这个消息的默认实现是直接抛出异常,如果重写了 forwardInvocation: 方法对调用进行了处理,程序就可以继续运行。

对于类方法则会调用相应的 resolveClassMethod: 方法来进行动态方法解析,之后按照这个过程进行消息的转发。