Runtime消息动态解析与转发流程
先上图:

下面根据具体代码看这张图。
一、创建一个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);
}
Runtime消息动态解析与转发流程的更多相关文章
- Objective-C RunTime 学习笔记 之 消息转发流程
1) 当向某个对象发送消息时,先从cache(cache_t)中查找方法对象(method_t),如果找到则进行回调:否则通过查找对象的类(元类)定义中方法列表,一直追溯到NSObject, 如果找到 ...
- runtime消息转发机制
Objective-C 扩展了 C 语言,并加入了面向对象特性和 Smalltalk 式的消息传递机制.而这个扩展的核心是一个用 C 和 编译语言 写的 Runtime 库.它是 Objective- ...
- Protobuf动态解析那些事儿
需求背景 在接收到 protobuf 数据之后,如何自动创建具体的 Protobuf Message 对象,再做反序列化.“自动”的意思主要有两个方面:(1)当程序中新增一个 protobuf Mes ...
- Runtime - 消息发送原理
Runtime - 消息发送原理. Objective-C运行时的核心就在于消息分派器objc_msgSend,消息分派器把选择器映射为函数指针,并调用被引用的函数. 要想理解objc_msgSend ...
- Protobuf动态解析在Java中的应用 包含例子程序
最近在做ProtoBuf相关的项目,其中用到了动态解析,网上看了下相关资料和博文都比较少,自己来写一个记录一下学习过程. Protocol Buffers是结构化数据格式标准,提供序列化和反序列方 ...
- Sentinel源码解析一(流程总览)
引言 Sentinel作为ali开源的一款轻量级流控框架,主要以流量为切入点,从流量控制.熔断降级.系统负载保护等多个维度来帮助用户保护服务的稳定性.相比于Hystrix,Sentinel的设计更加简 ...
- 使用Newtonsoft.Json.dll(JSON.NET)动态解析JSON、.net 的json的序列化与反序列化(一)
在开发中,我非常喜欢动态语言和匿名对象带来的方便,JSON.NET具有动态序列化和反序列化任意JSON内容的能力,不必将它映射到具体的强类型对象,它可以处理不确定的类型(集合.字典.动态对象和匿名对象 ...
- 理解AngularJS生命周期:利用ng-repeat动态解析自定义directive
ng-repeat是AngularJS中一个非常重要和有意思的directive,常见的用法之一是将某种自定义directive和ng-repeat一起使用,循环地来渲染开发者所需要的组件.比如现在有 ...
- 开源一个动态解析protobuf的工具
好久没写博客了,主要是这一年技术没啥长进都打杂了,还有就是生活琐事越来越多,人也越来越懒了…… 之前项目中用到了Protobuf,然后测试发现这玩意不好测,总不能每次定个协议或者改下都要编译Java代 ...
随机推荐
- Shell-2--输入输出重定向
自己写一下吧,免得又忘了,被人问到,被鄙视 0 表示标准输入, 1 表示标准输出 , 2 表示标准错误输出 一个 > 表示已覆盖的方式把命令的正确执行重定向到文件 两个 >> 表示是 ...
- 往github提交代码流程
一 首先在Github新建一个仓库,回到首页,点击右上角的New repository新建仓库. 二 在本地依次使用下面命令 …or create a new repository on the c ...
- Testing - 软件测试知识梳理 - 软件性能测试
软件性能测试的基本概念 软件的性能是软件的一种非功能特性,它关注的不是软件是否能够完成特定的功能,而是软件在完成该功能时展示出来的及时性. 软件性能的指标 响应时间:是指系统对请求作出响应的时间,并且 ...
- cracking the coding interview系列C#实现
原版内容转自:CTCI面试系列——谷歌面试官经典作品 | 快课网 此系列为C#实现版本 谷歌面试官经典作品(CTCI)目录 1.1 判断一个字符串中的字符是否唯一 1.2 字符串翻转 1.3 去除 ...
- RawConfigParser 与 ConfigParser ——Python的配件文件读取模块
一般情况都是使用ConfigParser这个方法,但是当我们配置中有%(filename)s这种格式的配置的时候,可能会出现以下问题: configparser.InterpolationMissin ...
- 疫苗:JAVA HASHMAP的死循环
在淘宝内网里看到同事发了贴说了一个CPU被100%的线上故障,并且这个事发生了很多次,原因是在Java语言在并发情况下使用HashMap造成Race Condition,从而导致死循环.这个事情我4. ...
- 关于vue-router,路由重定向的使用分析
看之前的项目,突然发现一个不算bug的bug,之前也是一直没有想到,现在发现之后越来越觉得有必要改掉, 项目用的是vue做的,自然切换用的就是路由,一级路由包括:首页.记录和个人中心,二级路由是在记录 ...
- SQL Server性能优化(9)聚集索引的存储结构
一.索引的概念和分类 索引的概念大家都知道,日常开发中我们也会使用常见的聚集索引.非聚集索引.但是除了这两者以外,sqlserver中还提供其他的索引,如: a. 唯一索引:不包含重复键的索引,聚集索 ...
- Mysql 用户权限管理
1. MySQL 权限介绍 mysql中存在4个控制权限的表,分别为user表,db表,tables_priv表,columns_priv表,我当前的版本mysql 5.7.22 . mysql权限表 ...
- 新手易犯的典型缺陷--C#
这段时间花了点时间整理了几个新手易犯的典型缺陷(专门针对C#的),但是个人的力量毕竟有限缺陷的覆盖面比较窄,有些缺陷的描述也不够准确,这里先贴出来看看能不能集思广益,收集整理出更多的典型缺陷.目标就是 ...