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代 ...
随机推荐
- 使用create-react-app 快速构建 React 开发环境以及react-router 4.x路由配置
create-react-app 是来自于 Facebook,通过该命令我们无需配置就能快速构建 React 开发环境. create-react-app 自动创建的项目是基于 Webpack + E ...
- 关于appendChild和insertBefore appendTo()和append
appendChild和insertBefore(原生js) appendTo()和append(jquery)
- (转)你真的会写单例模式吗——Java实现
http://www.runoob.com/design-pattern/singleton-pattern.html 单例模式可能是代码最少的模式了,但是少不一定意味着简单,想要用好.用对单例模式, ...
- 关于JS的一些东西
1.声明Js代码域 1.在head标签中使用script声明js代码域 <head> .... <!--声明js代码域--> ...
- 【Android】为需要支持API 11之前的Activity添加Action Bar的一种解决方案
首先汗一个,题目打出来我就觉得像是在写论文…… 家里生了个娃,好久没有写东西了…… 做Android开发有一个很头疼的地方就是随着sdk的演进,很多新东西被加进来.但由于这样那样的限制, 不是所有的新 ...
- win10 HTTP 错误 500.21 - Internal Server Error
错误描述: HTTP 错误 500.21 - Internal Server Error 处理程序“ExtensionlessUrlHandler-Integrated-4.0”在其模块列表中有一个错 ...
- Netty精粹之玩转NIO缓冲区
摘要: 在JAVA NIO相关的组件中,ByteBuffer是除了Selector.Channel之外的另一个很重要的组件,它是直接和Channel打交道的缓冲区,通常场景或是从ByteBuffer写 ...
- 深入理解kafka设计原理
最近开研究kafka,下面分享一下kafka的设计原理.kafka的设计初衷是希望作为一个统一的信息收集平台,能够实时的收集反馈信息,并需要能够支撑较大的数据量,且具备良好的容错能力. 1.持久性 k ...
- 史上最详细nodejs版本管理器nvm的安装与使用(附注意事项和优化方案)
使用场景 在Node版本快速更新迭代的今天,新老项目使用的node版本号可能已经不相同了,node版本更新越来越快,项目越做越多,node切换版本号的需求越来越迫切,传统卸载一个版本在安装另一个版本的 ...
- 微信分享JSSDK-invalid signature签名错误的解决方案
核对官方步骤,确认签名算法. 确认签名算法正确,可用 http://mp.weixin.qq.com/debug/cgi-bin/sandbox?t=jsapisign 页面工具进行校验. 确认con ...