先上图:

下面根据具体代码看这张图。

一、创建一个Person类,

Person.h

#import <Foundation/Foundation.h>@interface Person : NSObject-(void)sendMessage:(NSString *)message;@end

Person.m

#import "Person.h"
#import <objc/runtime.h>@implementation Person@end

大家可以看到,Person类只声明了 sendMessage:方法,在.m文件里没有实现这个方法。

这时,如果在viewController中调用Person类的sendMessage方法,程序会发生崩溃。

#import "ViewController.h"
#import "Person.h"@interface ViewController ()@end@implementation ViewController- (void)viewDidLoad {[super viewDidLoad];[[[Person alloc]init] sendMessage:@"Hello"];}

结合上面的图片,我们说说消息处理的机制。

1.当我们调用的方法没有具体的实现时,会调用

+ (BOOL)resolveInstanceMethod:(SEL)sel;

+(BOOL)resolveInstanceMethod:(SEL)sel{NSString *methodName = NSStringFromSelector(sel);if ([methodName isEqualToString:@"sendMessage:"]) {//我们可以在这里添加方法的实现return class_addMethod(self, sel, (IMP)sendMessage, "v@:@");}return NO;}void sendMessage (id self, SEL _cmd, NSString *message){NSLog(@"message=%@",message);
}

BOOL class_addMethod(Class cls, SEL name, IMP imp, const char *types):为类动态添加方法。如果有同名会返回NO,成功返回YES。

其中的参数types查询地址:(v:表示void, @:表示类型,等等)

2. 如果 resolveInstanceMethod:方法返回NO,调用

-(id)forwardingTargetForSelector:(SEL)aSelector;

这个方法是找备用者,比如:Animal类。

Animal.h

#import <Foundation/Foundation.h>@interface Animal : NSObject@end

Animal.m

#import "Animal.h"@implementation Animal-(void)sendMessage:(NSString *)message{NSLog(@"message=%@",message);
}@end

Animal类没有声明sendMessage:方法,但在.m文件里有这个方法的实现,可以作为备用者。如下:

-(id)forwardingTargetForSelector:(SEL)aSelector{NSString *methodName = NSStringFromSelector(aSelector);if ([methodName isEqualToString:@"sendMessage:"]) {if ([[Animal new] respondsToSelector:aSelector]) {return [Animal new];}}return [super forwardingTargetForSelector:aSelector];
}

3. 如果 forwardingTargetForSelector:(SEL)aSelector返回 nil。

// 若前两种方法都不处理,则走这里
//    1)方法签名
-(NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector{NSString *methodName = NSStringFromSelector(aSelector);if ([methodName isEqualToString:@"sendMessage:"]) {return [NSMethodSignature signatureWithObjCTypes:"v@:@"];}return [super methodSignatureForSelector:aSelector];
}
//  2) 签名后,消息转发,找备用者
-(void)forwardInvocation:(NSInvocation *)anInvocation{SEL selector = [anInvocation selector];Animal *animal = [Animal new];if ([animal respondsToSelector:selector]) {[anInvocation invokeWithTarget:animal];} else{[super forwardInvocation:anInvocation];}
}

4.如果走到第3步,仍然不做处理,如下:

-(void)forwardInvocation:(NSInvocation *)anInvocation{[super forwardInvocation:anInvocation];
}

这时为了程序的健壮性,防止崩溃,可以用以下方法处理。

//  若前3方法都不处理,为了防止崩溃,可调用此方法
-(void)doesNotRecognizeSelector:(SEL)aSelector{NSString *methodName = NSStringFromSelector(aSelector);NSLog(@"找不到 %@ 这个方法的实现",methodName);
}

附加源码

转载于:https://www.cnblogs.com/lfyDragon/p/9177710.html

Runtime消息动态解析与转发流程相关推荐

  1. runtime消息转发机制

    Objective-C 扩展了 C 语言,并加入了面向对象特性和 Smalltalk 式的消息传递机制.而这个扩展的核心是一个用 C 和 编译语言 写的 Runtime 库.它是 Objective- ...

  2. 基于`IRIS`,动态解析`HL7`消息

    文章目录 基于`IRIS`,动态解析`HL7`消息 什么是`HL7` `HL7` 版本 `HL7` 消息结构 段(`Segment`) 字段(`Field`) `HL7` 数据类型 在`IRIS`中查 ...

  3. iOS底层开发消息发送与转发流程

    iOS底层开发消息转发流程 一,cache缓存读取流程分析 首先我们上一章已经了解到对应的cache_t的数据结构 _bucketsAndMaybeMask:指针类型,存放buckets的首地址 _m ...

  4. Protobuf动态解析那些事儿

    2019独角兽企业重金招聘Python工程师标准>>> 需求背景 在接收到 protobuf 数据之后,如何自动创建具体的 Protobuf Message 对象,再做反序列化.&q ...

  5. 利用NAS免费部署动态解析实现内网穿透

    ‍ 想要从外网访问家中的NAS等设备,一般来说我们需要知道家中路由器的公网IP. 现在固定的公网IP基本上很难免费申请到了,但是一般来说运营商可以免费提供一个动态变化的公网IP:当路由设备重启时,运营 ...

  6. Protobuf动态解析

    阅读目录 需求背景 技术介绍 实现 总结 参考文献 回到顶部 需求背景 在接收到 protobuf 数据之后,如何自动创建具体的 Protobuf Message 对象,再做反序列化."自动 ...

  7. 【网络安全】Metasploit 生成的 Shellcode 的导入函数解析以及执行流程分析(1)

    2021 年 4 月,研究人员深入分析了 Cobalt Strike渗透测试技术,以及它的一些签名规避技术是如何在检测技术下失效的.在本文中,我们将深入讨论Metasploit,这是一个可以与Coba ...

  8. 路由器(结构、分组转发流程、路由选择协议(RIP、OSPF、BGP))

    1. 路由器的结构 从功能上可以划分为:路由选择和分组转发. 分组转发结构由三个部分组成:交换结构.一组输入端口和一组输出端口. 2. 路由器分组转发流程 从数据报的首部提取目的主机的 IP 地址 D ...

  9. NGFW中数据包转发流程

    状态检测防火墙报文处理流程 查询会话前的处理过程:基础处理 查询会话中的处理过程:转发处理,关键是会话建立 查询会话后的处理过程:安全业务处理及报文发送 了解转发流程之前,先给报文分个类 协议报文:使 ...

最新文章

  1. implementation ‘com.zxy.android:recovery:
  2. linux系统预定义变量有哪些,Shell预定义变量用法详解
  3. drf解决跨域问题 使用 django-corse-headers扩展
  4. 使用宝塔面板进行wordpress建站
  5. FSRNet:端到端深度可训练人脸超分辨网络
  6. Scikit-learn数据预处理分类变量编码之等级变量编码
  7. java中的model_Java程序员必看之springmvc中的Model对象在重定向中的数据
  8. 阿里巴巴旗下平台口碑推出无人收银技术,改造便利店市场;重庆法院运用 AI 探索“智能判案”...
  9. java get与post区别_HTTP请求(GET与POST区别)和响应
  10. C++ 11右值引用
  11. saas java框架_XMReport-提供web项目Java套打解决方案
  12. project不显示里程碑标志_在Project中设置里程碑
  13. php 重载进程,关于php-fpm与nginx进程重载
  14. TensorFlow——如何查看当前版本TF编译使用的CUDA和cuDNN的编译版本
  15. Java 线程——Timer TimerTask
  16. 惠普微型计算机怎么装机,台式小机惠普电脑怎么装系统
  17. 【经典策略系列】之 Dual Thrust 交易策略
  18. window10 tar解压
  19. swift ring
  20. java实现简单学生信息管理系统

热门文章

  1. 【转载】通过金矿模型介绍动态规划 (动态规划入门)
  2. 通过rsync搭建一个远程备份系统(二)
  3. 容器+AOP实现动态部署(四)
  4. Tomacat服务器的安装和配置
  5. 前端工具--less篇
  6. (转)动态Entity Framework查询:Dynamic Query 介绍
  7. Android Gallery控件使用方法详解
  8. Oracle lower() Upper()函数
  9. springboot 整合 mongodb实现 批量更新数据
  10. Bash : 索引数组