首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >ios OC 消息转发机制

ios OC 消息转发机制

原创
作者头像
conanma
修改于 2021-06-08 10:14:50
修改于 2021-06-08 10:14:50
91300
代码可运行
举报
文章被收录于专栏:正则正则
运行总次数:0
代码可运行

一 概述

     在编译期向类发送了其无法解读的的消息并不会报错,因为在运行期可以继续让类中添加方法,所有编译器在编译时还无法确知类中到底会不会有某个方法实现,当对象接收到无法解读的消息后,就会启动 消息转发 机制,程序员可经由此过程告诉对象应该如何处理未知消息。

在程序运行中,有时会以下异常信息

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
[Class function_name ] unrecognized selector sent to instanc

上段信息就是发送一个未识别的消息给实例,类定义但对象未实现function_name 方法

二 消息转发的两大阶段

    第一阶段先征询接受者所属的类,看其是否能动态添加方法,以处理当前“未知的选择子”,叫做“动态方法解析”。

    第二阶段涉及“完整的消息转发机制”,如果运行期系统已经把第一阶段执行完了,那么接受者自己就无法再以动态新增方法的手段来响应包含该选择子的消息了。此时,运行期系统会请求接受者以其他手段来处理与消息相关的调用方法。这又细分为两小阶段。首先,请接受者看看有没有其他对象能处理这条信息。若有,则运行期系统会把消息转给那个对象,于是消息转发过程结束。若没有“备援的接受者”,则启动完成的消息转发机制,运行期系统会把与消息有关的细节全部封装到NSInvocation对象中,让接受者最后一次设法解决当前还未处理的这条消息

2.1动态方法解析

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

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
+(BOOL)resolveInstanceMethod:(SEL)selector

该方法的参数就是未知的选择子,返回类型为Boolean,表示类是否能新增一个实例方法用以处理此选择子。在继续往下执行转换机制之前,本类可用新增处理此选择子的方法,假如尚未实现的方法不是实例方法而是类方法,那么运行期系统就会调用另外一个方法,该方法与“resolveInstanceMethod:”类似,叫做”resolveClassMethod:” 。

    使用这种办法的前提是:相关方法的代码实现已经写好,只等着运行的时候动态插在类里面就可以了。此方案常用来实现@dynamic 属性,比如要访问CoreData框架中NSManagedObjects对象的属性时就可用这么做,因为实现这些属性所需要的存取方法在编译器就能确定

2.2.1 备援接受者

    备援接受者为处理未知的选择子提供第二次机会,嫩故能把这条消息转给其他接受者来处理。该步骤对应的处理方法如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
-(id)forwardingTargetForSelector:(SEL)selector

方法参数代码未知的选择子,若当前接受者能找到备援对象,则将其返回,若找不到,就返回nil。通过次方案,我们可以用“组合”来模拟“多重继承”的某些特性。在一个对象内部,可能还有一系列其他对象,该对象可经由此方法将能够处理某选择子的相关内部对象返回,从外界看来,好像是该对象亲自处理这些消息。若是想在发送给备援接受者之前先修改消息内容,那就通过完整消息转发机制来做。

2.2.2 完整的消息转发

    如果转发算法到了这一步,那么唯一能做的就是启用完整的消息转发机制,首先创建NSInvocation对象,把尚未处理的那条消息有关的全部细节都封于其中。此对象包含选择子,目标及参数。在触发NSInvocation对象时,“消息派发系统”将会把消息指派给目标对象。

此步骤会调用下列方法来转发消息:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
-(void)forwardInvocation:(NSInvocation *)invocation

    该方法实现简单,只需要改变调用目标,使消息在新目标上得以调用即可。然而这样实现出来的方法与“备援接受者”方案所实现的方法等效,所有很少有人采用这么简单的实现方式。比较有用的实现方式为:在触发消息前,先以某种方式改变消息内容,比如追加另外一个参数,或是改变选择子。

    实现该方法时,若发现某调用操作不应由本类处理,则需要调用超类的同名方法。这样集成体系中的某个类都有机会处理此方法调用,直到NSObject,继而调用”doesNotRecognizeSelector:”以抛出异常,此异常表明选择子最终未能得到处理。

三 消息转发全流程

    接受者在每一步中均有机会处理信息。步骤越往后,处理消息的代价就越大,最好能在第一部就能处理完,这样,运行期系统就可以将方法缓存起来,如果这个类的实例稍后收到同名选择子,就武器启动消息转发流程。若想在第三部把消息转给备援接受者,还不如提前到第二步,因为第三步只是修改了调用目标,这项改动放在第二步执行更为简单,而且不用创建并处理完整的NSInvocation

四 总结

  • 若对象无法响应某个选择子,则进入消息转发机制
  • 通过运行期的 动态方法解析 功能,可以在需要用到某个方法时再将其加入类中
  • 对象可以把其无法解读的某些选择子转交给其他对象来处理(备援接受者\完整的消息转发)
  • 经过上述两步之后,如果还是没办法处理选择子,那就启动完整的消息转发机制

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
iOS进阶之消息转发机制
前言: iOS进阶之传递消息 上篇讲到消息传递,其中有个问题:对象在收到无法解读的消息之后会发生什么情况? 若想令类能理解某条消息,我们必须以程序码实现出对应的方法才行。但是,在编译期向类发送了
Dwyane
2018/05/22
9000
【iOS】运行时消息传递与转发机制
Objective-C是一门非常动态的语言,以至于确定调用哪个方法被推迟到了运行时,而非编译时。与之相反,C语言使用静态绑定,也就是说,在编译期就能决定程序运行时所应该调用的函数,所以在C语言中,如果某个函数没有实现,编译时是不能通过的。而Objective-C是相对动态的语言,运行时还可以向类中动态添加方法,所以编译时并不能确定方法到底有没有对应的实现,编译器在编译期间也就不能报错。
VV木公子
2018/06/05
8.5K0
iOS runtime探究(二): 从runtime开始深入理解OC消息转发机制你要知道的runtime都在这里
你要知道的runtime都在这里 转载请注明出处 https://cloud.tencent.com/developer/user/1605429 本文主要讲解runtime相关知识,从原理到实践,由于包含内容过多分为以下五篇文章详细讲解,可自行选择需要了解的方向: 从runtime开始: 理解面向对象的类到面向过程的结构体 从runtime开始: 深入理解OC消息转发机制 从runtime开始: 理解OC的属性property 从runtime开始: 实践Category添加属性与黑魔法method sw
WWWWDotPNG
2018/04/10
1K0
iOS runtime探究(二): 从runtime开始深入理解OC消息转发机制你要知道的runtime都在这里
对象、消息、运行期--12:runtime消息转发
2.通过运行期间的动态方法解析,可以再需要用到某个方法时再将其加入类中 3.对象可以把其无法解读的某些选择器转交给其他对象处理 4.经过上述两步,如果还是不能处理选择器,那就启动完整的消息转发机制
xy_ss
2023/11/22
2280
对象、消息、运行期--12:runtime消息转发
OC 消息机制及转发
这个错误提示几乎每个开发者都会遇到很多次,是由于给对象发送了一个无法识别的消息造成系统不能正常处理。
Light413
2020/04/08
7710
OC 消息机制及转发
理解消息转发机制
  消息转发分为两大阶段。第一阶段先征询接收者,所属的类,看其是否能动态添加方法,以处理当前这个“未知的选择子”(unknown selector),这叫做“动态方法解析”(dynamic method resolution)。第二阶段涉及“完整的消息转发机制”。如果运行期系统已经把第一阶段执行完了,那么接收者自己就无法再以动态新增方法的手段来响应包含该选择子的消息了。此时,运行期系统会请求接收者以其他手段来处理与消息相关的方法调用。这又细分为两小步。首先,请接收者看看有没有其他对象来处理这条消息。若有,则
王大锤
2018/05/17
9480
OC底层探索12-消息动态决议,方法慢速、快速转发OC底层探索12-消息动态决议,方法慢速、快速转发
如何打开该打印 可以通过查看log来发现实现了resolveInstanceMethod的方法
用户8893176
2021/08/09
5690
OC底层探索12-消息动态决议,方法慢速、快速转发OC底层探索12-消息动态决议,方法慢速、快速转发
《Effective Objective-C》干货三部曲(一):概念篇
本书是iOS程序员入门的必读书籍,它讲述了在iOS开发中(Objective-C语言)可以遵循的规范和一些开发技巧。
用户2932962
2018/08/30
1K0
《Effective Objective-C》干货三部曲(一):概念篇
iOS_Objective-C 消息发送(消息查找 及 消息转发)过程
​ 在对象上调用方法是Objective-C中常使用的功能,用OC的术语来说,叫“传递消息”(pass a message)。消息有“名称”(name)或“选择子”(selector),可以接收参数,而且可能还有返回值。
mikimo
2022/07/20
1.1K0
iOS_Objective-C 消息发送(消息查找 及 消息转发)过程
深入理解iOS消息转发机制
消息转发流程图 image 向一个对象发送消息时, 首先会在对象类的cache,method list以及父类对象的cache,method list依次查找SEL对应的IMP 如果没有找到,并
程序员不务正业
2018/06/13
1.7K0
iOS RunTime之四:消息转发
在消息转发机制执行前,Runtime 系统会再给我们一次偷梁换柱的机会,即通过重载 - (id)forwardingTargetForSelector:(SEL)aSelector 方法替换消息的接受者为其他对象:
s_在路上
2018/09/11
8540
iOS RunTime之四:消息转发
iOS 开发:『Runtime』详解(一)基础知识
我们都知道,将源代码转换为可执行的程序,通常要经过三个步骤:编译、链接、运行。不同的编译语言,在这三个步骤中所进行的操作又有些不同。
程序员充电站
2019/06/13
1.5K0
消息转发流程的源码探究
在上篇文章方法的查找流程——慢速查找中,在lookUpImpOrForward函数里面会进行方法的查找,如果最终没有找到,那么就会进入消息的转发流程,如下:
拉维
2021/03/10
6230
消息转发流程的源码探究
iOS底层原理总结 - 探寻Runtime本质(三)
方法调用的本质 本文我们探寻方法调用的本质,首先通过一段代码,将方法调用代码转为c++代码查看方法调用的本质是什么样的。 xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc main.m [person test]; // --------- c++底层代码 ((void (*)(id, SEL))(void *)objc_msgSend)((id)person, sel_registerName("test")); 通过上述源码可以看出c++底层代码
xx_Cc
2018/07/03
5660
OC-从方法的汇编层看消息转发流程
CacheLookup Normal,objc_msgSend(sel,imp)
Wilbur-L
2020/12/11
9300
OC-从方法的汇编层看消息转发流程
程序员面试时这样介绍自己的项目经验,成功率能达到98.99%
声明:面试是对自我审视的一种过程,面试题和iOS程序员本身技术水平没任何关联,无论你能否全部答出,都不要对自己产生任何正面或消极的评价!(面试题均来自群成员提供)
java爱好者
2019/06/18
1K0
(4)OC中消息和消息转发-02
上篇文章讲到,如果通过_class_resolveInstanceMethod和- (id)forwardingTargetForSelector:(SEL)aSelector还是没找到IMP,也就是
czjwarrior
2018/05/28
5010
cocoa动态方法决议及消息转发
假设给一个对象发送不能响应的消息,同一时候又没有进行动态方法决议,又没实现消息转发,那么就会引发以下的crash信息
全栈程序员站长
2022/07/14
3280
神经病院Objective-C Runtime住院第二天—消息发送与转发
现在越来越多的app都使用了JSPatch实现app热修复,而JSPatch 能做到通过 JS 调用和改写 OC 方法最根本的原因是 Objective-C 是动态语言,OC 上所有方法的调用/类的生成都通过 Objective-C Runtime 在运行时进行,我们可以通过类名/方法名反射得到相应的类和方法,也可以替换某个类的方法为新的实现,理论上你可以在运行时通过类名/方法名调用到任何 OC 方法,替换任何类的实现以及新增任意类。今天就来详细解析一下OC中runtime最为吸引人的地方。
一缕殇流化隐半边冰霜
2024/02/11
3230
神经病院Objective-C Runtime住院第二天—消息发送与转发
神经病院Objective-C Runtime住院第二天—消息发送与转发
现在越来越多的app都使用了JSPatch实现app热修复,而JSPatch 能做到通过 JS 调用和改写 OC 方法最根本的原因是 Objective-C 是动态语言,OC 上所有方法的调用/类的生成都通过 Objective-C Runtime 在运行时进行,我们可以通过类名/方法名反射得到相应的类和方法,也可以替换某个类的方法为新的实现,理论上你可以在运行时通过类名/方法名调用到任何 OC 方法,替换任何类的实现以及新增任意类。今天就来详细解析一下OC中runtime最为吸引人的地方。
一缕殇流化隐半边冰霜
2018/08/29
8190
神经病院Objective-C Runtime住院第二天—消息发送与转发
推荐阅读
相关推荐
iOS进阶之消息转发机制
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档