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中对象的「消息传递机制」.本文需要讲解另外一个重要问题:当对象受到无法处理的消息之后会发生什么情况? 显然,若想令类能理解某条消息 ...
随机推荐
- react native下android开发环境搭建
关于react native环境搭建我也是参考这篇文章的,但我这里就出现了很多在这篇文章里没有出现的问题,也是坑比较多.但最后在一位大神的帮助下还是成功运行了. 1.第一个坑就是有些文件下载需要VPN ...
- boi剖析 - 基于webpack的css sprites实现方案
本文是58到家前端工程化集成解决方案boi的博文系列之一.boi是基于webpack打造的一站式前端工程化解决方案,现已开源Github. 作为前端构建工具不可或缺的一个环节,自动生成css spri ...
- [python]在场景中理解装饰器
原来我也自己通过查资料,来学习python的装饰器,但是效果不好.因为没有接触过需要用到装饰器的场景,所以 一起的资料都只停留在纸面上,但是今天偶然看到了vimer的这篇文章:http://www.v ...
- Sprint总结
# Sprint 1 总结 > Sprint 1 主要是界面设计 > 为了遵循Material design,实际操作中依然遇到许多困难 > 预计耗时两小时每天,但是因为网络问题工作 ...
- 前端自动化工具 -- Gulp 使用简介
gulp是基于流的前端自动化构建工具. 之前也谈到了 grunt的用法,grunt其实就是配置+配置的形式. 而gulp呢,是基于stream流的形式,也就是前一个函数(工厂)制造出结果,提供后者使用 ...
- Equeue初识
详细解说: http://www.cnblogs.com/netfocus/p/3595410.html 简单代码用法: Producer 端代码用法实例 和 Customer 端代码用法示例: ht ...
- sql server2008中左连接,右连接,等值连接的区别
数据库中的连接我了解到有left join,right join,inner join这些,以下是它们的区别: 1)左连接(left join):先取出a表的所有数据,再取出a.b表相匹配的数据 2) ...
- X3DOM新增剪裁平面节点ClipPlane支持
裁剪平面由方程Ax+By+Cz+D=0确定.所有满足[A B C D]M-1[Xe Ye Ze We]T>0的人眼坐标[Xe Ye Ze We]的点都位于该平面定义的半空间中,而该半空间以外的所 ...
- fibonacci数列从a到b的个数
Description 我们定义斐波那契数列如下: f1=1 f2=2 f(n)=f(n-1)+f(n-2)(n>=3) 现在,给定两个数a和b,计算有多少个斐波那契数列中的数在a和b之间( ...
- (旧)子数涵数·DW——图文混排页面
一.首先,打开Dreamweaver,新建一个的HTML项目. 二.在设计区里,写一些文字,随便写一点(也可以在代码区中的<body>和</body>之间写). 三.插入一张图 ...