深入理解Object-C消息转发机制

iOS runtime探究(二): 从runtime开始深入理解OC消息转发机制 你要知道的runtime都在这里转载请注明出处 http://www.jianshu.com/p/eac6ed137e06本文主要讲解runtime相关知识,从原理到实践,由于包含内容过多分为以下五篇文章详细讲解,可自行选择需要了解的方向: 从runtime开始: 理解面向对象的类到面向过程的结构体 从runtime开始: 深入理解OC消息转发机制 从runtime开始: 理解OC的属性proper 阅读详情

相信大家对Object-C的消息传递机制并不陌生(如果不熟悉,我后续会再写一篇关于消息传递机制的文章),今天我来讲解另外一个重要的问题,就是对象在收到无法解读的消息之后会发生什么情况。

若想令类能理解某条消息,我们必须以程序码实现出对应的方法才行。但是,在编译器向类发送了其无法解读的消息并不会报错,因为在运行期可以继续向类中添加方法(动态添加),所以编译器在编译时还无法确知类中到底会不会有某个方法实现。当对象接收到无法解读的消息后,就会启动“消息转发”(message forwarding)机制,程序员可经由此过程告诉对象应该如何处理未知消息。

你可能早就遇到过经由消息转发流程所处理的消息了,只是未加留意。如果在控制台中看到下面这种提示信息,那就说明你曾向某个对象发送过一条无法解读的消息,从而启动了消息转发机制,并将次消息转发给了NSObject得默认实现。

1
2
3
4
5
-[__NSCFNumber lowercaseString]:unrecognized selector 
sent to instance 0x87
*** Terminating app due to uncaught exception
'NSInvalidArgumentException',reason:
'-[__NSCFNumber lowercaseString]:unrecognized selector sent to instance ox87'

上面这段异常信息是由NSObject的“doesNotRecognizeSelector:”方法所抛出的,此异常表明:消息接收者的类型是__NSCFNumber,而该接受者无法理解名位lowercaseString的选择子。本例所列举的这种情况并不奇怪,因为NSNumber类里本来就没有名为lowercaseString的方法。在本例中,消息转发过程以应用程序崩溃而告终,不过,开发者在编写自己的类时,可于转发过程中设置挂钩,用以执行预定的逻辑,而不使应用程序崩溃。

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

动态方法解析


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

1
+ (BOOL)resolveInstanceMethod:(SEL)sel

该方法的参数就是那个未知的选择子,其返回值为Boolean类型,表示这个类是否能新增一个实例方法用以处理此选择子。在继续往下执行转发机制之前,本类有机会新增一个处理此选择子的方法。加入尚未实现的方法不是实例方法而是类方法,那么运行期系统就会调用另外一个方法

1
+ (BOOL)resolveClassMethod:(SEL)sel

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

备援接收者


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

1
- (id)forwardingTargetForSelector:(SEL)aSelector

方法参数代表未知的选择子,若当前接收者能找到被援对象,则将其返回,若找不到就返回nil。在一个对象内部,可能还有一系列其他对象,该对象可经由此方法将能够处理某选择子的相关内部对象返回,这样的话,在外界看来,好像是该对象亲自处理了这些消息似的。

完整的消息转发


如果转发算法已经来到这一波的话,那么唯一能做的就是启用完整的消息转发机制了。首先创建NSInvocation对象,把与尚未处理的那条消息有关的全部细节都封于其中。在触发NSInvocation对象时,“消息派发系统”将亲自出马,把消息指派给目标对象。

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

1
-(void)forwardInvocation:(NSInvocation *)invocation

这个方法实现很简单:只需改变调用目标,使消息在新目标上得以调用即可。然而这样实现出来的方法与“备援接收者”方案实现的方法等效,所以很少有人采用这么简单的实现方式。 

以完整的例子演示动态方法解析


下面编写一个类似于“字典”的对象。

在接口文件中随便定义几个属性:

1
2
3
4
@interface GXZDictionary : NSObject
@property (nonatomic,strong) NSString *name;
@property (nonatomic,strong) NSNumber *number;
@property (nonatomic,strong) NSDate *date;

本例的关键在于resolveInstanceMethod:方法的实现代码:

1
@dynamic name,number,date;
1
2
3
4
5
6
7
8
9
10
 + (BOOL)resolveInstanceMethod:(SEL)selector
{
NSString *selectorString = NSStringFromSelector(selector);
if ([selectorString hasPrefix:@"set"]) {
class_addMethod(self, selector, (IMP)autoDictionarySetter, "v@:@");
} else {
class_addMethod(self, selector, (IMP)autoDictionaryGetter, "@@:");
}
return YES;
}

然后就是Getter和Setter方法实现了: 

getter:

1
2
3
4
5
6
7
id autoDictionaryGetter(id self,SEL _cmd)
{
GXZDictionary *typedSelf = (GXZDictionary *)self;
NSMutableDictionary *backingStore = typedSelf.backingStore;
NSString *key = NSStringFromSelector(_cmd);
return [backingStore objectForKey:key];
}

其中的backingStore是实现文件中定义的可变的字典,用于存储数据。

下面是Setter方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
void autoDictionarySetter(id self,SEL _cmd,id value)
{
GXZDictionary *typedSelf = (GXZDictionary *)self;
NSMutableDictionary *backingStore = typedSelf.backingStore;
NSString *selectorString = NSStringFromSelector(_cmd);
NSMutableString *key = [selectorString mutableCopy];
[key deleteCharactersInRange:NSMakeRange(key.length - 1, 1)];
[key deleteCharactersInRange:NSMakeRange(0, 3)];
NSString *lowercaseFirstChar = [[key substringToIndex:1] lowercaseString];
[key replaceCharactersInRange:NSMakeRange(0, 1) withString:lowercaseFirstChar];
if (value) {
[backingStore setObject:value forKey:key];
} else {
[backingStore removeObjectForKey:key];
}
}

好了,主要工作已经完成,下面直接使用就可以了,调用很简单:

1
2
3
GXZDictionary *dict = [GXZDictionary new];
dic.date = [NSDate dateWithTimeIntervalSince1970:475372800];
NSLog(@"%@",dict.date);

好了,是不是很神奇,很简单,现在可以随便在接口文件中添加属性了。

小结


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

转:http://coderperson.com/2015/06/08/iOS-runtime-messageForwarding/#以完整的例子演示动态方法解析

深入理解Objective-C Runtime消息传递机制 Objective-C的动态性核心在于其运行时消息传递机制,它将方法调用解耦为SEL(方法选择器)、IMP(函数实现指针)与objc_msgSend(消息分发引擎)三要素。该机制基于动态绑定而非静态链接,使KVO、Method Swizzling、消息转发等高级特性成为可能。其技术价值体现在灵活性与可扩展性上——支持运行时方法解析、继承链查找、缓存加速及三层容错转发。典型应用场景包括AOP埋点、动态代理、崩溃兜底与内存调试。本文聚焦objc_msgSend执行流程、SEL/IMP本质及消息转发三阶段策略,揭 阅读详情

相关推荐

iOS消息转发机制深度解析与项目实战应用

在iOS开发中,消息转发机制是Objective-C运行时系统的核心特性之一。当一个对象接收到其类或实例未实现的方法调用时,系统并不会立即抛出异常,而是进入一系列的消息转发流程,尝试为该消息寻找合适的处理者。这一机制极大地增强了程序的灵活性和动态性。消息转发不仅在底层支撑着KVO、代理(Delegate)、方法交换(Method Swizzling)等功能的实现,还在实际项目中广泛应用于插件化架构设计、接口兼容性适配、动态模块加载等场景。

weixin_35370061的博客 942

【OC底层_消息发送与转发机制原理】

OC一直以来被称为动态语言,Objective-C 是一门动态的语言,在学习KVO和KVC的时候就能理解一些了,当然不单单是因为这个特质,OC还具有动态绑定动态类型等特点,接下来学习的消息传递和消息转发机制就能深刻的体会这些特别的动态特点。简单理解一下动态绑定和动态类型的意思当在对象上调用方法在Objective-C里面非常普遍,这个就叫给某个对象发送消息,消息有名称或者选择子这个说法,消息也不单单可以接受参数,还可以有返回值。

weixin_61639290的博客 1661

深入理解Objective-C消息机制与关联对象

本篇博客深入探讨了Objective-C中消息机制的工作原理,特别是objc_msgSend函数的动态绑定特性和消息转发机制。通过代码示例,展示了如何在运行时动态添加方法实现以及关联对象的内存管理策略。博客最后强调了在实际开发中,应当谨慎使用关联对象,以免引入难以察觉的bug。

weixin_28922227的博客 499

inBuilder今日分享丨Object-C消息转发与发送机制

Objective-C 是一门动态语言,它将很多静态语言在编译和链接时期做的事情,推迟到了运行时来处理。当我们调用一个方法时会通过运行时(Runtime)来绑定、分发。它的运行时(Runtime)实现了对类、方法、成员变量、属性等信息的动态管理,给我们在编码时极大的灵活性。结合出现的问题,分享下运行时中的方法的调用、拦截过程。本篇中用的到Runtime函数发送消息获取类对象获取父类获取方法。

m1024292777的博客 298

开源网格划分软件-Gmsh二次开发教程 (4)网格生成与控制​

​本章将深入讲解Gmsh的网格生成技术,包括全局/局部网格控制、边界层生成、自适应细化等,并提供完整的代码示例。

ZQGG的博客 1472

Windows服务器XMRig挖矿病毒深度清除实战指南

XMRig是一种广泛用于Monero(XMR)加密货币挖矿的开源工具,其在Windows环境中的持久化机制已远超传统木马范畴,融合WMI事件订阅、服务伪装、PowerShell无文件执行与注册表隐写等多重反检测技术。理解其基于行为而非特征的生存逻辑,是实现有效检测与根除的前提。该技术具备强隐蔽性、高自愈性与网络通信合法化特征,常见于RDP弱口令爆破、SMB共享泄露及PowerShell远程执行等非漏洞类入侵场景。本文聚焦Windows原生命令与Sysinternals工具链,提供覆盖进程定位、WMI清理、服

weixin_30535843的博客 730

Objective-C消息发送和消息转发机制

消息发送 在Objective-C中,使用对象进行方法调用是一个消息发送的过程(Objective-C采用“动态绑定机制”,所以所要调用的方法直到运行期才能确定)。例如: id returnValue = [someObject messageName:parameter]; 其中,someObject是消息的“接收者”,messageName为“选择子”,“选择子”与参数合起来叫做消息

sheng_bin的博客 467

Matlab机械臂建模:机器人工具箱的使用&&导入自己的机械臂模型

本文主要介绍如何在matlab中建立机械臂模型(前提要下载了Robotics Toolbox机器人工具箱~),并进行基于正逆运动学计算的轨迹运动。对于已有的Solidworks机械臂三维模型,如何导入Matlab,并对其进行运动控制。

m0_46427461的博客 5万+

最新 Objective-C objc_msgSend 消息发送底层原理

首先判断消息接收者是否为nil nil直接返回 如果消息接收者是实例对象 它通过isa 到它的类对象的方法缓存cache(哈希表)中查找 O(1) 如果消息接收者是类对象 它就通过isa 到它的元类对象中查找 如果方法缓存cache找不到就到class_rw_t的方法列表中查找 如果方法列表是有序的 二分查找 O(logN) 方法列表没有序 就普通线性遍历查找 O(N) 如果找到了就调用方法 结束查找 并把方法 缓存到缓存列表中 如果没找到且有父类就继续 到父类查找 重复上面的过程 直到基类N.

weixin_41963895的博客 506

scannet数据集下载文件

scannet数据集下载文件 由于大家会申请scannet数据集,审批比较慢,我将下载的文件里面的内容贴出来,大家可以复制放进py文件中,运行就可以下载 ps:别再私信要数据集了,这个自己下载,如果光三维数据的话,还是很快的,当然如果路由器翻了墙的话,下载会更快。 #!/usr/bin/env python # Downloads ScanNet public data release # Run with ./download-scannet.py (or python download-scannet.

weixin_40766438的博客 9228

产品包装质检实战:基于YOLOv5的智能包装合格检测系统全流程指南

摘要: 针对产品包装质检效率低、漏检率高的问题,本文提出基于YOLOv5的智能检测系统。系统通过采集包装缺陷数据(破损、缺标、封装不良等),利用YOLOv5实现多类别缺陷识别(准确率≥95%),并开发Flask Web界面实现检测可视化与报告生成。实验表明,该系统在30帧/秒的产线速度下可稳定运行,显著提升质检效率。项目涵盖数据标注、模型训练、系统开发全流程,具有工业落地价值,适用于智能制造场景的自动化质检需求。(149字)

LXY_LOVE36的博客 92

深入理解windows 消息机制

深入理解Windows消息机制 今天我们来学一学Windows消息机制,我们知道在传统的C语音程序中,当我们需要打开一个文件时,我们可以调用fopen()函数,这个函数最后又会调用操作系统提供的函数以此来打开文件。而在Windows编程中,不仅用户可以调用系统的API函数,反之,系统也可以调用应用程序,而这些调用就是通过Windows的消息机制来实现的。Windows程序设计是

liulianglin的专栏 3万+

《UDS协议从入门到精通》系列——图解0x83:访问时间参数

详细介绍UDS协议0x83服务,目标ECU的时序参数设置有哪些注意点?

车载系统攻城狮 2138

U盘免格式化装系统:Ventoy 免费启动盘

周二晚上十点半,老同学发来语音,说公司电脑进不去系统,重要资料还在里面,急着要一只启动盘救场。我翻出抽屉里那几只U盘,全是当年写盘写剩的,插上去才知道哪只还能用。格式化、写镜像、校验、拔插,这套流程我走了快十年,今晚实在不想再走一遍。后来固定用一个方案:Ventoy,免费开源的启动盘工具,装一次,之后只往盘里拷镜像。 ## 传统写盘 vs Ventoy:省掉的不只是格式化 传统做法是把镜像整个

gitblog_00789的博客 1267

手把手教你学Simulink--基于未来出行解决方案的场景实例:电动飞行汽车(eVTOL)的动力系统建模与仿真

电动垂直起降飞行器零道路拥堵:三维空间飞行绿色低碳:全电驱动,零排放快速响应:城市内15分钟直达低噪音:相比直升机↓20dB📊 预测:2030年全球eVTOL市场规模将超300亿美元,中国、美国、欧洲加速适航认证。本文通过,构建了电动飞行汽车(eVTOL)动力系统高压电池系统建模电力电子(DC-DC、逆变器)实现PMSM电机+螺旋桨推进系统搭建完整飞行任务动态仿真性能KPI评估与优化。

MHD0815的博客 438

【UML】第12篇 序列图(1/2)——基本概念和构成

序列图(Sequence Diagram)是一种用于显示对象之间交互的图形化表示。它描述了在特定场景下,对象之间按照时间顺序进行的消息传递和协作过程。在序列图中,对象被表示为带有垂直虚线的矩形,虚线表示对象的生命周期。对象之间的交互通过箭头表示的消息来表示,箭头从一个对象的生命线指向另一个对象的生命线,表示消息的发送和接收。

AI人人懂 3044

iOS-Tips高级技巧:深入理解Runtime与消息转发机制

作为一名iOS开发者,你是否曾好奇Objective-C中的方法调用是如何工作的?为什么我们可以动态地向对象发送消息?这一切都归功于iOS Runtime机制和消息转发机制。今天,我将为你深入解析iOS开发中的Runtime核心原理,帮助你掌握Objective-C的动态特性,提升你的iOS开发技能。 ## 📱 什么是iOS Runtime? iOS Runtime是Objective-C语

gitblog_01082的博客 415

汉书HE8,好用的汇编代码编写工具

汉书HE8,好用的汇编代码编写工具早期编写汇编代码所用功能强大

iOS 深入理解Runtime运行原理,即消息发送和消息转发

发送给对象的名称和一组参数。在Objective-C中方法调用是一个消息发送的过程。消息转发是一种功能强大的技术,可以大大增加Objective-C的表现力。什么是消息转发?简而言之,它允许未知的消息被困住并作出反应。换句话说,无论何时发送未知消息,它都会以一个很好的包发送到您的代码中,此时您可以随心所欲地执行任何操作。注意:当我们向一个对象发(实例方法,即减号方法)送消息时,runtime会在这个对象所属的这个类的方法列表中查找方法;

CallAuxiliary Blog 514

lwip-2.0.3

lwip是瑞典计算机科学院(SICS)的Adam Dunkels 开发的一个小型开源的TCP/IP协议栈。实现的重点是在保持TCP协议主要功能的基础上减少对RAM 的占用。

IMSL CNL 7.0.0 (x86-64)Crack

IMSL CNL 7.0.0 (x86-64)Crack intel的算法库破解文件,这是C++版本的破解文件

iOS Runtime运行机制详解(消息传递、消息转发)

一直想发关于Runtime的文章,但是由于读的资料一多,对Runtime的理解又加深了一些,所以总是改来改去,导致一篇都没发出来(其实是因为懒)。 最近又有小伙伴问我,我也只好再次补老账了。。。 ---------啥是OC Runtime---------- OC Runtime呢,其实就是一个Runtime库。 (那啥是Runtime库呢?给你个小链接:https://www.cnblo...

ws1836300的博客 1719

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

iOS runtime消息转发机制

1、概念: 当消息的接受者找不到对应的方法selector,就会启动消息转发机制。 2、消息转发机制分为三步: 1、动态方法解析 2、备用接受者 3、完整消息转发 3、详解: 第一步:通过调用+ (BOOL)resolveInstanceMethod:(SEL)sel或者+ (BOOL)resolveClassMethod:(SEL)sel看是否对消息转发进行处理,若这一步对消息进行...

jbr5740的专栏 436

深入理解Windows消息机制

今天我们来学一学Windows消息机制,我们知道在传统的C语言程序中,当我们需要打开一个文件时,我们可以调用fopen()函数,这个函数最后又会调用操作系统提供的函数以此来打开文件。而在Windows编程中,不仅用户可以调用系统的API函数,反之,系统也可以调用应用程序,而这些调用就是通过Windows的消息机制来实现的。Windows程序设计是一种完全不同于传统的DOS方式的程序设计方法,它是一...

qq_33263769的博客 930

runtime NSProxy 消息转发

oc中调用方法其实就是向对象发送消息,在编译Objective-C函数调用的语法时,会被翻译成一个C的函数调用:objc_msgSend(),例如: 那么,objc_msgSend又做了哪些事呢?,以[object foo]为例:1.通过object的isa指针找到它的class2.在class的method_list中找到foo3.如果clas...

jing091111的博客 127

ios-消息转发机制

关于消息转发机制可能用到的也不是很多,但是在这里也记录下,它的几个用法。如果我们想让一个类没有实现的方法想让另一个类去做,其实就要用到消息转发的机制了。 就好比我们有一个Person类,如果这个类声明了eat方法但是没有去实现这个eat方法,然后我们在创建一个Person类对象的时候,然后去调用eat方法,程序毫无疑问会崩溃。 关于消息转发首先有几个方法我们需要去知道的就是下面的这几个方法

rv0p111 414

深入理解Objective-C的Runtime机制

觉得还不错的一篇关于Runtime的文。

ybcy0612的博客 433
上一篇: iOS runtime理解
下一篇: iOS开发-Runtime详解
直隶码农
博客等级 码龄19年 95粉丝 103原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值