Runtime-消息发送和消息转发
消息发送
消息发送举例:下面这个OC代码
[person read:book];
会被编译成:
objc_msgSend(person, @selector(read:), book);
objc_msgSend的具体流程如下:
- 通过isa指针找到所属类
- 查找类的cache列表, 如果没有则下一步
- 查找类的”方法列表”
- 如果能找到与选择子名称相符的方法, 就跳至其实现代码
- 找不到, 就沿着继承体系继续向上查找
- 如果能找到与选择子名称相符的方法, 就跳至其实现代码
- 找不到, 执行”消息转发”.
消息转发
上面我们提到, 如果到最后都找不到, 就会来到消息转发,消息转发的流程如下:
- 动态方法解析 : 先问接收者所属的类, 你看能不能动态添加个方法来处理这个”未知的消息”? 如果能, 则消息转发结束.
- 备胎(后备接收者) : 请接收者看看有没有其他对象能处理这条消息? 如果有, 则把消息转给那个对象, 消息转发结束.
- 消息签名 : 这里会要求你返回一个消息签名, 如果返回nil, 则消息转发结束.
- 完整的消息转发 : 备胎都搞不定了, 那就只能把该消息相关的所有细节都封装到一个NSInvocation对象, 再问接收者一次, 快想办法把这个搞定了. 到了这个地步如果还无法处理, 消息转发机制也无能为力了。
1. 动态方法解析
对象在收到无法解读的消息后, 首先调用其所属类的这个类方法 :
+ (BOOL)resolveInstanceMethod:(SEL)selector
// selector : 那个未知的选择子
// 返回YES则结束消息转发
// 返回NO则进入备胎
假如尚未实现的方法不是实例方法而是类方法, 则会调用另一个方法resolveClassMethod:
2. 备胎
动态方法解析失败, 则调用这个方法
- (id)forwardingTargetForSelector:(SEL)selector
// selector : 那个未知的消息
// 返回一个能响应该未知选择子的备胎对象
通过备胎这个方法, 可以用”组合”来模拟出”多重继承”.
3. 消息签名
备胎搞不定, 这个方法就准备要被包装成一个NSInvocation对象, 在这里要先返回一个方法签名
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector
// NSMethodSignature : 该selector对应的方法签名
4. 完整的消息转发
给接收者最后一次机会把这个方法处理了, 搞不定就直接程序崩溃!
- (void)forwardInvocation:(NSInvocation *)invocation
// invocation : 封装了与那条尚未处理的消息相关的所有细节的对象
在这里能做的比较现实的事就是 : 在触发消息前, 先以某种方式改变消息内容, 比如追加另外一个参数, 或是改变消息等等. 实现此方法时, 如果发现某调用操作不应该由本类处理, 可以调用超类的同名方法. 则继承体系中的每个类都有机会处理该请求, 直到NSObject. 如果NSObject搞不定, 则还会调用doesNotRecognizeSelector:来抛出异常, 此时你就会在控制台看到那熟悉的unrecognized selector sent to instance..
上面这4个方法均是模板方法,开发者可以override,由runtime来调用。最常见的实现消息转发,就是重写方法3和4,忽略这个消息或者代理给其他对象.
Runtime-消息发送和消息转发的更多相关文章
- RocketMQ源码 — 三、 Producer消息发送过程
Producer 消息发送 producer start producer启动过程如下图 public void start(final boolean startFactory) throws MQ ...
- 微信小程序发送模板消息
微信小程序发送模板消息 标签(空格分隔): php 看小程序文档 [模板消息文档总览]:https://developers.weixin.qq.com/miniprogram/dev/framewo ...
- RocketMQ 消息发送system busy、broker busy原因分析与解决方案
目录 1.现象 2.原理解读 2.1 RocketMQ 网络处理机制概述 2.2 pair.getObject1().rejectRequest() 2.3 漫谈transientStorePoolE ...
- 【RocketMQ源码学习】- 3. Client 发送同步消息
本文较长,代码后面给了方法简图,希望给你帮助 发送的方式 同步发送 异步发送 消息的类型 普通消息 顺序消息 事务消息 发送同步消息的时序图 为了防止读者朋友嫌烦,可以看下时序图,后面我也会给出方法的 ...
- Orleans 客户端请求的消息流转以及消息在Silo中再路由机制
1.客户端是一个OutSideRuntimeClient,在这个客户端类中有一个消息代理中心transport(类型为ProxiedMessageCenter) 2.ProxiedMessageCen ...
- (二)RabbitMQ消息队列-RabbitMQ消息队列架构与基本概念
原文:(二)RabbitMQ消息队列-RabbitMQ消息队列架构与基本概念 没错我还是没有讲怎么安装和写一个HelloWord,不过快了,这一章我们先了解下RabbitMQ的基本概念. Rabbit ...
- iOS 消息发送与转发详解
Objective-C 是一门动态语言,它将很多静态语言在编译和链接时期做的事情,放到了运行时来处理.之所以能具备这种特性,离不开 Runtime 这个库.Runtime 很好的解决了如何在运行时期找 ...
- Runtime - 消息发送原理
Runtime - 消息发送原理. Objective-C运行时的核心就在于消息分派器objc_msgSend,消息分派器把选择器映射为函数指针,并调用被引用的函数. 要想理解objc_msgSend ...
- 理解Objective-C Runtime(三)消息转发机制
消息转发机制概述 上一篇博客消息传递机制中讲解了Objective-C中对象的「消息传递机制」.本文需要讲解另外一个重要问题:当对象受到无法处理的消息之后会发生什么情况? 显然,若想令类能理解某条消息 ...
随机推荐
- python框架之Django(7)-Cookie&Session使用
Cookie 添加 response.set_cookie 添加明文cookie response.set_cookie(key, value='', max_age=None, expires=No ...
- [js]this关键字代表当前执行的主体
点前是谁,this就是谁 <div id="div1" class="div1"></div> <div id="div ...
- arithmetic-02
Java collection API 中实现的表ADT: collection<E>接口实现继承iterable<E>接口,实现iterable接口的类可以使用增强for循环 ...
- scrapy流程图
refer:https://blog.yongli1992.com/2015/02/08/python-scrapy-module/ 这里是一张Scrapy架构图的展示.Scrapy Engine负责 ...
- 学习使用scrapy itemspipeline过程
开始非常不理解from https://www.jianshu.com/p/18ec820fe706 找到了一个比较完整的借鉴,然后编写自己的煎蛋pipeline 首先在items里创建 image_ ...
- Future 示例
public static Object send(RequestClient request) future.channel().writeAndFlush(JSONObject.toJSONStr ...
- Poj2386 Lake Counting (DFS)
Lake Counting Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 49414 Accepted: 24273 D ...
- (转) 为什么不应该重写service方法?
故事通常是这样开始的: 从前,有一个程序猿,他语重心长地对孙子说:“孩子,要是你以后写servlet,最好不要重写service方法啊” 孙子大为不解,程序猿又说:“听爷爷的,准没错,爷爷的爷爷就是这 ...
- 数据挖掘算法——Close算法
说明奥:菜鸟的自我学习,可能有错. Close算法原理: 一个频繁闭合项目集的所有闭合子集一定是频繁的,一个非频繁闭合项目集的所有闭合超集一定是非频繁的. close算法是对Apriori算法的改进 ...
- html5+PHP,websocket无法连接的问题(Call to undefined function socket_create())
首先是配置文件的问题,打开extension=php_gd2.dll和extension=php_sockets.dll 扩展. 主要注意的是你当前系统使用的php版本和环境变量里面的php版本是否一 ...