第十二条:理解消息转发机制
上一条我们说了对象的消息传递机制很重要,那么问题来了----对象在收到无法解读的消息之后会发生什么呢?
若想令类能理解某条消息,我们必须以程序码实现出对应的方法才行。
但是,在编译器向类发送了其无法解读的消息并不会报错,因为在运行期可以继续向类中添加方法,所以编译器在编译时还无法确知类中到底会不会有某个方法实现。
当对象接收到无法解读的消息后,就会启动“消息转发”(message forwarding)机制,程序员可经由此过程告诉对象应该如何处理未知消息。
消息转发过程分为两大阶段:
第一阶段先征询接收者,所属的类,看其是否能动态添加方法,以处理当前这个“未知的选择子”(unknown selector),这叫做“动态方法解析”(dynamic method resolution)。
第二阶段涉及“完整的消息转发机制”(full forwarding mechanism)。如果运行期系统已经把第一阶段执行完了,那么接收者自己就无法再以动态新增方法的手段来响应包含该选择子的消息了。
此时,运行时系统会请求接收者以其他手段来处理与消息相关的方法调用。
这又分为两步:首先,请接收者看看有没有其他对象能处理这条消息。
若有,则运行时系统会把消息转给那个对象,于是消息转发过程解析,一切正常。
若没有“备援的接受者”(replacement receiver),则启动完整的消息转发机制,运行时系统会把与消息有关的全部细节都封装到NSInvocation对象中,再给接收者最后一次机会,令其设法解决当前还未处理的这条消息。
动态方法解析
对象在收到无法解读的消息后,首先将调用其所述类的下列类方法:
+(BOOL)resolveInstanceMethod:(SEL)selector;
该方法的参数就是那个未知的选择子,其返回值为Boolean类型,表示这个类是否能新增一个实例方法用以处理此选择子。
再继续往下执行转发机制之前,本类有机会新增一个处理此选择子的方法。
假如尚未实现的方法不是实例方法而是类方法,那么运行期系统就会调用另外一个方法,该方法与“resolveInstanceMethod:”类似,叫做“resolveClassMethod”。
使用这种办法的前提是:相关方法的实现代码已经写好,只等着运行的时候动态插在类里面就可以了。
此方案常用来实现@dynamic属性
要点:
1.若对象无法响应某个选择子,则进入消息转发流程。
2.通过运行期的动态方法解析功能,我们可以在需要用到某个方法时再将其加入类中。
3.对象可以把其无法解读的某些选择子转交给其他对象来处理。
4.讲过上述两步之后,如果还没办法处理选择子,那就启动完整的消息转发机制。