runtime之消息转发
前言
在上一篇文章中我们初尝了runtime的黑魔法,可以在程序编译阶段就获取到成员变量的名字,特性以及动态的给对象增加属性等等,在接下来中我们进一步了解OC的消息发送机制。如果之前没接触过runtime的同学建议先看看:上一篇《runtime之玩转成员变量》
OC的消息发送机制是早有耳闻,鉴于自己一直觉得是很底层的东西需要花大量的时候去学习研究它所以一直都是蠢蠢欲动。同样不做过多铺垫,直接切入吧。当我们使用OC对象调用一个方法的时候,比如这样:[lisi sayHello]; 程序运行的时候会转化为runtime的代码objc_msgnSend(lisi,@selector(sayHello)),通过消息发送函数的字面意义我们可以知道是给lisi这个对象发送了sayHello这个消息。方法的调用其实就是给类发送一个消息,调用类方法也一样,类实际上也是一个对象,是元类的实例。runtime中类似这种消息发送的函数还有很多包括:
objc_property_t *class_copyProperty(Class cls,unsigned int *outcout) //获取所有的属性列表
Method *class_copyMethodList(Class cls,unsigned int *outCount) //获取所有方法的数组
Bool class_addMethod (Class cls,SEL name,IMP imp,const char *type) //添加方法
消息转发流程:
当我们创建一个实例变量并调用实例方法时候,即[receiver message],转换为运行时代码id objc_msgSend(id self,SEL op....),首先根据实例的isa指针到指定的类中的方法列表中进行查找相应的op,如果找到相应的op则调用,如果找不到的话则到相应的父类中查找,这样一直循环上去,一直到根类NSObject中如果还没有找到的话会按照优先级从高到低调用下面三个函数:
+ resolveInstanceMethod:(SEL)sel // 对应实例方法没有获取到
+ resolveClassMethod:(SEL)sel // 对应类方法没有获取到
2 - (id)forwardingTargetForSelector:(SEL)aSelector
3 - (void)forwardInvocation:(NSInvocation *)anInvocation
即某一个实例方法的本类及其父类都没有实现的时候会首先调用+ resolveInstanceMethod:(SEL)sel,如果该方法没有实现则调用- (id)forwardingTargetForSelector:(SEL)aSelector,如果第二个方法还没有实现的时候就调用第三个- (void)forwardInvocation:(NSInvocation *)anInvocation。若是这三个方法都没有实现的话则程序抛出异常。
注意:第三个方法(void)forwardInvocation:(NSInvocation *)anInvocation需要跟methodSignatureForSelector结合使用才能实现消息转发,methodSignatureForSelector的作用是为一个类已经实现的方法创建一个有效的签名。
消息转发的原理:
每个类都有一个包含SEL和对应的IMP的Method列表,也就是说一个Method包含着一个SEL和一个对应的IMP,而消息转发就是将原本的SEL和IMP的这种对应关系给分开,跟其他的Method重新组合。
下面通过一个Person类体验实现runtime的消息转发:
1,动态添加函数实现消息转发:
Person.h添加下面在这个方法并且在Person.m文件中不实现它:
- (void)goForWork;
在Person.m中实现消息转发:
+(BOOL)resolveInstanceMethod:(SEL)sel
{
NSString *selString = NSStringFromSelector(sel);
if ([selString isEqualToString:@"goForWork"]) {
/**
* 为类中没有实现的方法添加一个函数实现
*
* @param self 类名
* @param goForWork 没有实现的方法
* @IMP workFunc 添加的函数实现
* @ "v@:" TypeEncoding函数类型的类型编码
* @return
*/
class_addMethod(self, @selector(goForWork), (IMP)workFunc, "v@:");
}
return [super resolveInstanceMethod:sel];
} void workFunc(id self,SEL sel)
{
NSLog(@"Person go for work");
}
在外界调用Person实例的goForWalk 方法,可以看见打印台打印:
2,切换消息接受者实现消息转发:
将消息给其他对象也是消息转发的一种形式,一般是将消息转发给该对象中其他对象,这样子看起来也就感觉是该对象执行了该方法。我们在Person类中定义一个Dog类型的变量myDog。同样的,在Person定义一个walk方法并且不实现,Dog类同样定义这样的一个方法并在implement中实现。
Person.m中重写forwardingTargetForSelector:转换消息接收者:
-(id)forwardingTargetForSelector:(SEL)aSelector
{
NSString *selString = NSStringFromSelector(aSelector);
if ([selString isEqualToString:@"walk"]) {
self.myDog = [Dog new];
return self.myDog;
}
return [super forwardingTargetForSelector:aSelector];
}
外界调用后可以在打印台中:

转换消息对象方式二:
methodSignatureForSelector:和forwardInvocation:结合实现消息转发。
-(NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector
{
NSMethodSignature *methodSignature = [super methodSignatureForSelector:aSelector];
if (!methodSignature) {
methodSignature = [Dog instanceMethodSignatureForSelector:aSelector];
}
return methodSignature;
} - (void)forwardInvocation:(NSInvocation *)anInvocation
{
if ([Dog instancesRespondToSelector:anInvocation.selector]) {
//消息调用
[anInvocation invokeWithTarget:self.myDog]; }
}
通过这种方式同样能够在打印台打印出相同结果。
runtime之方法交换实现:
当我学习到runtime这个移魂大法的时候不禁惊叹runtime大法好,简直是黑魔法,同时心里产生一点邪恶的心里
runtime之消息转发的更多相关文章
- iOS Runtime的消息转发机制
前面我们已经讲解Runtime的基本概念和基本使用,如果大家对Runtime机制不是很了解,可以先看一下以前的博客,会对理解这篇博客有所帮助!!! Runtime基本概念:https://www.cn ...
- OC:浅析Runtime中消息转发机制
一.介绍 OC是一门动态性语言,其实现的本质是利用runtime机制.在runtime中,对象调用方法,其实就是给对象发送一个消息,也即objc_msgSend().在这个消息发送的过程中,系统会进行 ...
- Runtime 运行时之一:消息转发
解释一 上一篇文章咱们提到了Runtime的消息传递机制,主要围绕三个C语言API来展开进行的.这篇文章我将从另外三个方法来描述Runtime中另一个特性:消息转发机制. 一.消息转发机制 当向某个对 ...
- iOS开发·runtime原理与实践: 消息转发篇(Message Forwarding) (消息机制,方法未实现+API不兼容奔溃,模拟多继承)...
本文Demo传送门: MessageForwardingDemo 摘要:编程,只了解原理不行,必须实战才能知道应用场景.本系列尝试阐述runtime相关理论的同时介绍一些实战场景,而本文则是本系列的消 ...
- objc_msgSend消息传递学习笔记 – 消息转发
该文是 objc_msgSend消息传递学习笔记 – 对象方法消息传递流程 的基础上继续探究源码,请先阅读上文. 消息转发机制(message forwarding) Objective-C 在调用对 ...
- iOS消息转发
消息转发是一种功能强大的技术,可以大大增加Objective-C的表现力.什么是消息转发?简而言之,它允许未知的消息被困住并作出反应.换句话说,无论何时发送未知消息,它都会以一个很好的包发送到您的 ...
- iOS runtime探究(二): 从runtime開始深入理解OC消息转发机制
你要知道的runtime都在这里 转载请注明出处 http://blog.csdn.net/u014205968/article/details/67639289 本文主要解说runtime相关知识, ...
- runtime消息转发机制
Objective-C 扩展了 C 语言,并加入了面向对象特性和 Smalltalk 式的消息传递机制.而这个扩展的核心是一个用 C 和 编译语言 写的 Runtime 库.它是 Objective- ...
- 理解Objective-C Runtime(三)消息转发机制
消息转发机制概述 上一篇博客消息传递机制中讲解了Objective-C中对象的「消息传递机制」.本文需要讲解另外一个重要问题:当对象受到无法处理的消息之后会发生什么情况? 显然,若想令类能理解某条消息 ...
随机推荐
- UBUNTU上的GIT SERVER
Git是一个开源的版本控制系统,由Linus Torvalds主导,用于支持Linux内核开发.每一个Git工作目录,都是一个完整的代码库,包含所有的提交历史.有能力跟踪所有的代码版本,而不会去依赖于 ...
- Tools - Notepad++
NotePad++ https://notepad-plus-plus.org/ 修改主题 依次点击设置---语言格式设置---选择主题,在显示界面中修改相关设置(背景色.前景色.字体等). 双文本横 ...
- 基于openssl的单向和双向认证
1.前言 最近工作涉及到https,需要修改nginx的openssl模块,引入keyless方案.关于keyless可以参考CloudFlare的官方博客: https://blog.cloudfl ...
- 【推荐】iOS集合视图的可重新排序的layout
在实际项目中你或许会遇到在一个集合视图中移动一项到另外一个位置,那么此时我们需要对视图中的元素进行重新排序,今天推荐一个很好用的第三方类LXReorderableCollectionViewFlowL ...
- WatiN框架学习
WatiN 是一个源于 Watir的工具,开源且用于web测试自动化的类库.Web Application Testing in .NET. WatiN 通过与浏览器的交互来实现自动化,使用起来具有轻 ...
- Dell_r720服务器部署
没错,就是它--> 前言:本来是写在word文档上作为笔记的,想想觉得不能浪费我在机房被狂虐两天总结出来的这点小经验, 还是分享一下吧,说 ...
- jquery选择器(原创)<三>
现在来看看表单域选择器 1.:input选择器 :input选择器,用于选择所有Input,textarea,select和button元素,语法格式如下: $(":input") ...
- Python打包-py2exe使用
Py2exe 64位下载地址:http://download.csdn.net/detail/henujyj/8532827 Py2exe 32位下载地址:https://sourceforge.ne ...
- java阻塞队列
对消息的处理有些麻烦,要保证各种确认.为了确保消息的100%发送成功,笔者在之前的基础上做了一些改进.其中要用到多线程,用于重复发送信息. 所以查了很多关于线程安全的东西,也看到了阻塞队列,发现这个模 ...
- 最小生成树Prim算法(邻接矩阵和邻接表)
最小生成树,普利姆算法. 简述算法: 先初始化一棵只有一个顶点的树,以这一顶点开始,找到它的最小权值,将这条边上的令一个顶点添加到树中 再从这棵树中的所有顶点中找到一个最小权值(而且权值的另一顶点不属 ...