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中对象的「消息传递机制」.本文需要讲解另外一个重要问题:当对象受到无法处理的消息之后会发生什么情况? 显然,若想令类能理解某条消息 ...
随机推荐
- GET方法传递中文参数乱码解决办法
1.在页面中对你的URL进行编码 使用------encodeURI(你要使用的中文参数值)如:...?username"+encodeURI(“小甜甜") 2.在后台通过解码来接 ...
- 爬虫技术 -- 基础学习(三)理解URL和URI的联系与区别
网络爬虫的基本操作是抓取网页.首先要了解下URL~~ 在理解URL之前,先了解下URI,这两个概念我曾经混淆过~@_@|| 什么是URI? Web上每种可用的资源,如:html文档.视频,图片等都由一 ...
- java--实现将文字生成二维码图片,并在中间附上logo,下方附上文字
前段时间因为工作需要,要实现将一段文字或者url生成二维码,然后中间附上logo,下方正中间附上文字的功能. 上网找了几篇教程学习了下,由于没有保存借鉴的博文链接,所以就没po上参考文章的链接啦,感谢 ...
- Unity3D 敌人AI 和 动画( Animator )系统的实例讲解
在这个实例中,我们要做一些敌人AI的简单实现,其中自动跟随和动画是重点,我们要达到的目标如下: 1.敌人能够自动跟随主角 2.敌人模型一共有四个动作:Idle(空闲) Run(奔跑) Attack(攻 ...
- weblogic集群中获取jndi的方式
# The following example specifies a list of WebLogic Servers using the same port: ht.put(Context.PRO ...
- Web 项目可能会用到的20款优秀的开源工具
开源的应用程序和它们的源代码可以免费获得,因为版权是属于任何进行过修改或者提交代码的人.大多数提供开源软件的公司都可以建立行业标准,因此可以获得有利的竞争优势. 很多的开源应用程序和工具都有很强的替代 ...
- Laravel 5 事件的使用
事件类通常被保存在 app/Events 目录下,而它们的处理程序则被保存在 app/Handlers/Events 目录下. 事件的创建 下面我们用artisan来创建一个事件,比如叫CqhTest ...
- UWP开发入门(十七)——判断设备类型及响应VirtualKey
蜀黍我做的工作跟IM软件有关,UWP同时会跑在电脑和手机上.电脑和手机的使用习惯不尽一致,通常我倾向于根据窗口尺寸来进行布局的变化,但是特定的操作习惯是依赖于设备类型,而不是屏幕尺寸的,比如聊天窗口的 ...
- HTML--Table布局
<DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" Content= ...
- ASP.NET中使用DropDownList实现无刷新二级联动详细过程
Demo.sql create table Car( [id] int identity, ) not null, ) not null ) go insert into Car ([brand],[ ...