理解消息转发机制

  消息转发分为两大阶段。第一阶段先征询接收者,所属的类,看其是否能动态添加方法,以处理当前这个“未知的选择子”(unknown selector),这叫做“动态方法解析”(dynamic method resolution)。第二阶段涉及“完整的消息转发机制”。如果运行期系统已经把第一阶段执行完了,那么接收者自己就无法再以动态新增方法的手段来响应包含该选择子的消息了。此时,运行期系统会请求接收者以其他手段来处理与消息相关的方法调用。这又细分为两小步。首先,请接收者看看有没有其他对象来处理这条消息。若有,则运行期系统会把消息转发给那个对象,于是消息转发过程结束,一切如常。若没有“备援的接收者”,则启动完整的消息转发机制,运行期系统会把与消息有关的全部细节都封装在NSInvocation对象中,再给接收者最后一次机会,令其设法解决当前还未处理的这条消息。

  注意:选择子就是方法,就是@selector(methodName)这个玩意,也叫方法选择器。

  一,动态方法解析

  对象在收到无法解读的消息后,首先将调用其所属类的下列类方法:

+  (BOOL)resolveInstanceMethod:(SEL)selector

  该方法的参数就是那个未知的选择子,其返回值为Boolean类型,表示这个类是否能新增一个实例方法用以处理此选择子。

  如果是类方法,则会调用:

+ (BOOL)resolveClassMethod:(SEL)selector

使用这种方法的前提是:相关方法的实现代码已经写好,只等运行的时候动态插在类里面就可以了。

  二,完整的消息转发

  如果运行期系统已经执行完了动态方法解析,消息还没有被处理,那么消息接受者自己就无法再以动态新增方法的形式来响应包含该未知选择子的消息了,此时就进入了第二阶段——完整的消息转发。运行期系统会请求消息接受者以其他手段来处理与消息相关的方法调用。

  1 备援接收者

  当前接收者还有第二次机会能处理未知的选择子,在这一步中运行期系统会问它:能不能把这条消息转给其他接收者来处理。就会调用如下方法:

- (id)forwardingTargetForSelector:(SEL)selector

这里的返回值,就是备援接收者,它会继续处理这个消息。

在一个对象内部,可能还有一系列其他对象,该对象可经由此方法将能够处理某选择子的相关内部对象返回,这样的话,在外界看来,好像是该对象亲自处理了这些消息似的。

  2 完整的消息转发

  如果消息还没有被处理,转发算法就会来到这一步。首先创建NSInvocation对象,把尚未处理的那条消息有关的全部细节都封装其中。“消息派发系统”将把消息指派给目标对象。这里的目标对象可以自定义。此步骤会调用下列方法:

 (void)forwardInvocation:(NSInvocation *)invocation

实现此方法时,如果发现调用操作不应该由本类处理,则需要沿着继承体系,调用父类的同名方法,这样一来,继承体系中的每个类都有机会处理这个调用请求,直至rootClass,也就是NSObject类。如果最后调用了NSObject的类方法,那么该方法还会继而调用”doesNotRecognizeSelector:“以抛出异常,此异常表明选择子最终也未能得到处理。消息转发到此结束。

关于does NotRecognizeSelector:你可能感到陌生,但是对于类似于unrecognized selector send to instance xxx这样的错误,你可能并不陌生。这种错误通常是因为调用了某个对象或者某个类里不存在的方法,从而触发了消息转发机制,最终把这个未识别的消息发送给了NSObject的默认实现。

三,消息转发全流程:

摘录自《Effetive Objective-C 2.0 编写高质量iOS与OS X代码的52个有效方法》第12条:理解消息转发机制

DEMO1:https://github.com/caigee/iosdev_sample下的ClassForward

DEMO2:https://github.com/huanglonghui/MessageForwardingTest

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏java一日一条

正确使用Java事件通知

让我们从一个最简单的 Java Bean 开始,它叫StateHolder,里面封装了一个私有的 int 型属性state 和常见的访问方法:

2131
来自专栏令仔很忙

UML之状态图

  状态:是指在对象生命周期中满足某些条件、执行某些活动或等待某些事件的一个条件和状况。

3581
来自专栏Java后端技术栈

Java虚拟机OOM之虚拟机栈和本地方法栈溢出(4)

(1)如果线程请求的栈深度大于虚拟机所允许的深度,将抛出StackOverflowError 异常; (2)如果虚拟机栈可以动态扩展(当前大部分的 Java ...

843
来自专栏微信公众号:Java团长

深入理解Java虚拟机到底是什么

作为一个Java程序员,我们每天都在写Java代码,我们写的代码都是在一个叫做Java虚拟机的东西上执行的。但是如果要问什么是虚拟机,恐怕很多人就会模棱两可了。...

1553
来自专栏JAVA高级架构

深入理解Java虚拟机到底是什么

什么是Java虚拟机 作为一个Java程序员,我们每天都在写Java代码,我们写的代码都是在一个叫做Java虚拟机的东西上执行的。但是如果要问什么是虚拟机,恐怕...

3077
来自专栏枕边书

搭建自己的PHP框架心得(一)

前言 说到写PHP的MVC框架,大家想到的第一个词--“造轮子”,是的,一个还没有深厚功力的程序员,写出的PHP框架肯定不如那些出自大神们之手、经过时间和各种项...

3467
来自专栏XAI

【Python3-API】情感倾向分析示例代码

Python3-urllib3-API情感倾向分析示例代码 AccessToken获取可以参考:http://ai.baidu.com/forum/topic/...

3339
来自专栏工科狗和生物喵

【计算机本科补全计划】Java学习笔记(一) 安装配置 (Mac Sublime3) 红黄蓝

正文之前 标题后面为啥要加三个字呢。蹭热度不至于,就想着,让更多人知道么。毕竟我以后也会有当爸的一天~ 要是那些人渣站在悬崖上,旁边没啥人看着,我上去踢一脚是做...

3887
来自专栏Crossin的编程教室

【Python 第38课】 模块

如果说我比别人看得更远些,那是因为我站在了巨人的肩上。 -- 牛顿 python自带了功能丰富的标准库,另外还有数量庞大的各种第三方库。使用这些“巨人的”代码...

28510
来自专栏求索之路

从零开始仿写一个抖音App——Apt代码生成技术、gradle插件开发与protocol协议

本文首发于简书——何时夕,搬运转载请注明出处,否则将追究版权责任。交流qq群:859640274

1994

扫码关注云+社区

领取腾讯云代金券