Objective-C消息转发机制详解

消息转发机制的出现

            回想一下,在我们日常的程序开发中,是不是经常会遇到下面这种情况:

自定义的Atom类
示例

        我们自定义了一个类,然后再程序中调用某个方法,但是这个方法在该类中找不到相应实现,系统提示我们unrecognized selector sent to instance,表明该对象无法解读此消息,但作为一门高级的编程语言,难道Objective-C不做任何事就会让程序崩溃掉吗,答案当然是...不可能!作为一门动态语言,Objective-C充分的利用了它的语言特性,在程序运行期间通过一些方法来给开发者机会阻断程序这样的崩溃,给对象和消息更多的机会来完成成功的调用,而这其中所用用到的技术就是消息转发机制。

什么是消息转发机制

        消息转发机制,听起来好像很厉害的一个概念,那么消息转发机制到底是什么意思呢,我的理解是消息转发机制就是系统为了更好的解决对象收到无法解读的消息这件事,然后自己创建出的一个模式,包含了一系列方法,就像程序崩溃前的防守阵营一样,用来阻止程序直接走向崩溃。下面用一张图来形象的展示一下消息转发机制的构成:

消息转发机制

       由图中可以直观的看到,消息转发机制主要包含三个步骤:

        1:动态方法解析阶段

        2:备用接收者阶段

        3:完整消息转发阶段

        如果程序经过这三个阶段之后都没能解读所调用的消息,那么程序会调走向最后的灰色提示,doesNotRecognizeSelector方法,抛出异常,需要注意一点的是,上面三个步骤,越往后,处理消息的代价越大。好啦,下面我们就来具体介绍一下这三个步骤吧!

动态方法解析阶段

       这是消息转发的第一阶段,处在这个阶段的时候,主要有两个方法来帮你解决问题:

       1:+(BOOL)resolveClassMethod:(SEL)sel

       2:+(BOOL)resolveInstanceMethod:(SEL)sel

      顾名思义,当方法是类方法时调用1,当方法为实例方法时,调用2。这个方法设计的目的是为了给类利用 class_addMethod 添加方法的机会。下面来看一下具体实现的例子:

示例

由代码可知,在Atom类中我并未定义一个名为instanceTest的实例方法,所以编译器报了黄色的警告,但我在Atom的实现文件中通过+(BOOL)resolveInstanceMethod:(SEL)sel这个方法在运行时动态的添加了方法的实现,最终程序正常运行。

        关于class_addMethod(__unsafe_unretained Class cls, SEL name, IMP imp, const char *types)方法:

这里对于这个方法的参数做一点补充:

cls:被添加方法的目标类

name:新方法的选择器

imp:实现这个方法的函数的地址

types:描述方法参数的数据类型的字符串,例如这个例子中我写的id functionForInstance(id self,SEL _cmd),就对应“@@:”,这种表达方式叫Type Encodings,是官方定义好的,更全的展示我在这贴两张官方的图:

type encodings
method encodings

备用接收者阶段

        这是消息转发的第二阶段,如果第一阶段没有成功,就会来到这个阶段,在这个阶段主要利用的方法是- (id)forwardingTargetForSelector:(SEL)aSelector,此时,运行时询问能否把消息转给其他接收者处理,也就是此时系统给了个将这个 SEL 转给其他对象的机会,具体示例如图所示:

示例

我们新定义了一个类,名为Helper,在该类中我们实现了instanceTest实例方法,当系统运行时在Atom类中找不到方法的相应实现,于是来到- (id)forwardingTargetForSelector:(SEL)aSelector这个方法,请求备用者响应,如果备用者能响应则将此消息转给新对象执行。

完整消息转发阶段

      如果前两个阶段都不能解决问题,系统就会来到最后这个第三阶段,完整消息转发阶段,这是消息转发流程的最后一个环节,与第二阶段不同,此阶段可以将消息转发给多个对象,这个阶段主要利用的方法是- (void)forwardInvocation:(NSInvocation *)anInvocation,但是注意一点,使用这个方法必须同时重写- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector这个方法,消息转发机制使用从这个方法中获取的信息来创建NSInvocation对象,具体示例如图:

Helper实现文件
Helper2实现文件
Atom实现文件
示例

      在这个例子中,我们新建了一个Helper2类,同样实现了instanceTest实例方法,可以看到,在这个例子中最后程序顺利执行了,同时Helper和Helper2都响应了这条消息,同时也能发现,最后的返回值是最后一个处理消息转发对象的对应方法的返回值。

     补充一点,关于methodSignatureForSelector,methodSignatureForSelector用于描述被转发的消息,系统会调用methodSignatureForSelector:方法,尝试获得一个方法签名。如果获取不到,则直接调用doesNotRecognizeSelector抛出异常。如果能获取,则返回非nil:创建一个 NSlnvocation 并传给forwardInvocation:。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 198,932评论 5 466
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,554评论 2 375
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 145,894评论 0 328
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,442评论 1 268
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,347评论 5 359
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 47,899评论 1 275
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,325评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,980评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,196评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,163评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,085评论 1 328
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,826评论 3 316
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,389评论 3 302
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,501评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,753评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,171评论 2 344
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,616评论 2 339

推荐阅读更多精彩内容

  • 转至元数据结尾创建: 董潇伟,最新修改于: 十二月 23, 2016 转至元数据起始第一章:isa和Class一....
    40c0490e5268阅读 1,673评论 0 9
  • 消息发送和转发流程可以概括为:消息发送(Messaging)是 Runtime 通过 selector 快速查找 ...
    lylaut阅读 1,805评论 2 3
  • 我们常常会听说 Objective-C 是一门动态语言,那么这个「动态」表现在哪呢?我想最主要的表现就是 Obje...
    Ethan_Struggle阅读 2,161评论 0 7
  • 本文详细整理了 Cocoa 的 Runtime 系统的知识,它使得 Objective-C 如虎添翼,具备了灵活的...
    lylaut阅读 789评论 0 4
  • 转载:http://yulingtianxia.com/blog/2014/11/05/objective-c-r...
    F麦子阅读 723评论 0 2