iOS消息传递机制和消息转发机制

引言

    objective-c是一门动态语言,是c语言的超集。在c语言中,编译期间就必须根据代码执行的顺序决定运行时期的执行结果。在编译结束之后就知道代码最终会走进哪一个方法。在objectvie-c中,方法是动态绑定的,对象在运行过程中根据消息转发机制对相应的方法做出响应。

iOS消息传递

    一般来说消息传递是指对象在进行方法调用时,如果在该对象中找不到对应的方法实现,就会到改对象的父类中查找对应的方法实现。如果找到则继续执行下去。如果没有找到继续到父类中寻找对应的方法实现,如果到基类中还是没有找到对应的方法实现,则会触发消息转发机制。

1
id returnValue = [someObject messgeName:parameter];

    上面示例中,someObject是方法调用着,messaName是方法名,也称为selector(选择子),选择子和其所带的参数合称为消息。运行过程中,编译器会将商法消息转化为objc_msgSend()进行调用。原型如下:

1
2
void objc_msgSend(id self, SEL cmd, ...)
`

    第一个参数是方法调用者,第二个参数是选择子(应该是指向对应c语言方法实现的一个指针),后面的可变参数是消息所携带的参数。

消息传递完整流程:

    1、方法调用者根据isa指针找到自己所属类的方法列表,首先会去cache中查找是否有方法实现,如果有则找到直接运行。如果没有则道方法列表中寻找对应的方法实现。如果该类实现了这个方法,那么会将这个方法加入到cache中,并执行这个方法。

    2、如果在该类的方法别表中找不到对应的方法实现,会到这个类的父类中使用相同的方式查找相对应的方法实现。

    3、如果到基类中都没有找到objc_msgSend()中的选择子的方法。那么将会触发消息转发机制。

iOS消息转发

    在开发过程中经常会遇到,xxx: unrecognized selector sent to instance,类似报错都是iOS方法在触发消息转发机制后,找不到对应的方法实现抛出的问题。其完成的流程图如下:

ios消息转发流程

    从图中可以看到,消息转发主要包括三个步骤

1、 method resolution

2、 fast forwarding

3、 normal forwarding

如果想要最后不会抛出unrecognized selector的异常,那么就必须在消息转发中的某一个步骤拯救。

method resolution

    如果调用了实例方法会进行+(BOOL)resolveInstanceMethod:(SEL)sel判断,如果调用了类方法,则会进行+(BOOL)resolveClassMethod:(SEL)sel,返回yes则表示可以进行消息处理,否则进入到第二步。

fast forwarding

    如果第一步返回NO,进入
-(id)forwardingTargetForSelector:(SEL)aSelector,并在其中使用替代的类型方法去响应。

Normal forwarding

    如果第2步返回self或者nil,则说明没有可以响应的目标 则进入第三步。
第三步的消息转发机制本质上跟第二步是一样的都是切换接受消息的对象,但是第三步切换响应目标更复杂一些,第二步里面只需返回一个可以响应的对象就可以了,第三步还需要手动将响应方法切换给备用响应对象。

1
(1)-(NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector