先上图:

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

一、创建一个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消息动态解析与转发流程的更多相关文章

  1. Objective-C RunTime 学习笔记 之 消息转发流程

    1) 当向某个对象发送消息时,先从cache(cache_t)中查找方法对象(method_t),如果找到则进行回调:否则通过查找对象的类(元类)定义中方法列表,一直追溯到NSObject, 如果找到 ...

  2. runtime消息转发机制

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

  3. Protobuf动态解析那些事儿

    需求背景 在接收到 protobuf 数据之后,如何自动创建具体的 Protobuf Message 对象,再做反序列化.“自动”的意思主要有两个方面:(1)当程序中新增一个 protobuf Mes ...

  4. Runtime - 消息发送原理

    Runtime - 消息发送原理. Objective-C运行时的核心就在于消息分派器objc_msgSend,消息分派器把选择器映射为函数指针,并调用被引用的函数. 要想理解objc_msgSend ...

  5. Protobuf动态解析在Java中的应用 包含例子程序

    最近在做ProtoBuf相关的项目,其中用到了动态解析,网上看了下相关资料和博文都比较少,自己来写一个记录一下学习过程.   Protocol Buffers是结构化数据格式标准,提供序列化和反序列方 ...

  6. Sentinel源码解析一(流程总览)

    引言 Sentinel作为ali开源的一款轻量级流控框架,主要以流量为切入点,从流量控制.熔断降级.系统负载保护等多个维度来帮助用户保护服务的稳定性.相比于Hystrix,Sentinel的设计更加简 ...

  7. 使用Newtonsoft.Json.dll(JSON.NET)动态解析JSON、.net 的json的序列化与反序列化(一)

    在开发中,我非常喜欢动态语言和匿名对象带来的方便,JSON.NET具有动态序列化和反序列化任意JSON内容的能力,不必将它映射到具体的强类型对象,它可以处理不确定的类型(集合.字典.动态对象和匿名对象 ...

  8. 理解AngularJS生命周期:利用ng-repeat动态解析自定义directive

    ng-repeat是AngularJS中一个非常重要和有意思的directive,常见的用法之一是将某种自定义directive和ng-repeat一起使用,循环地来渲染开发者所需要的组件.比如现在有 ...

  9. 开源一个动态解析protobuf的工具

    好久没写博客了,主要是这一年技术没啥长进都打杂了,还有就是生活琐事越来越多,人也越来越懒了…… 之前项目中用到了Protobuf,然后测试发现这玩意不好测,总不能每次定个协议或者改下都要编译Java代 ...

随机推荐

  1. spring boot、cloud v2.1.0.RELEASE 使用及技术整理

    2018年10月30日 springboot v2.1.0.RELEASE 发布: https://github.com/spring-projects/spring-boot/releases/ta ...

  2. 花了一晚上时间,终于把Python的基本用法归纳好了!

    一.内置函数 1. complex([real[,imag]]) 返回一个复数,实部 + 虚部*1j,或者把字符串或者数字转成复数形式. 参数可以是复数表达式,也可以是字符串.当参数是字符串的时候,数 ...

  3. 哥们,你真以为你会做这道JVM面试题?

    有关Java虚拟机类加载机制相关的文章一搜一大把,笔者这里也不必再赘述一遍了. 笔者这里捞出一道code题要各位大佬来把玩把玩,如果你一眼就看出了端倪,那么恭喜你,你可以下山了: public cla ...

  4. HoloLens开发手记 - 使用Visual Studio Using Visual Studio

    不论你是否使用DirectX或Unity来开发全息应用,你都会使用Visual Studio 2015来进行调试和部署应用.在本部分,你将会学习以下内容: 如何通过Visual Studio将你的应用 ...

  5. call、apply、bind的用法

    数组追加 //用apply拼接 var arr1=[12,'name:foo',2048]; var arr2=['Joe','Hello']; Array.prototype.push.apply( ...

  6. android UI:Fragment碎片

    碎片(Fragment) 嵌入与活动中的UI片段,为了合理的分配布局而存在,这是我的简单理解.多用于兼顾手机与平板的UI,也适用于灵活高级的UI制作. Demo 简单的按键切换两片不同的Demo 新建 ...

  7. Django--分页器(paginator)

    1 Django的分页器(paginator)简介 在页面显示分页数据,需要用到Django分页器组件 from django.core.paginator import Paginator Pagi ...

  8. msysGit在GitHub代码托管

    (转:http://www.cnblogs.com/xing901022/p/4388190.html) 代码的管理,在日常开发中是很重要的环节,程序员的修炼三部曲——版本控制,单元测试,项目自动化. ...

  9. mysql 开发进阶篇系列 36 工具篇mysqlshow(数据库对象查看工具)

    一.概述 mysqlshow客户端查找工具,能很快地查找存在哪些数据库,数据库中的表,表中的列或索引,和mysql客户端工具很类似,不过有些特性是mysql客户端工具所不具备的. mysqlshow的 ...

  10. window下安装绿色版5.7

    1. 在mysql的安装目录下创建my.ini,并配置必要参数. 2. 执行命令mysqld --initialize-insecure --basedir=/opt/mysql/mysql  --d ...