消息转发机制

在上一篇文章中,我们了解了方法的慢速查找流程以及动态方法决议,在动态方法决议之后其实还不会崩溃,后面还会走到消息转发流程, 这一篇文章就来了解一下消息的转发机制。

在讲解消息转发机制之前,我们先来补充一下类方法的动态决议。

resolveMethod_locked

由图可以看出,对象方法直接调用了resolveInstanceMethod, 然而类方法调用完resolveClassMethod还有一个判断条件,如果需要查找cls类中有该方法的实现还会走一次resolveInstanceMethod,为什么会这样呢?

这里是因为类方法在元类中是对象方法的形式存在,所以还是需要查询元类中的对象方法。但由于我们无法在元类里面进行操作,所以只能根据元类的走向,最终会来到NSObject,可以在NSObject里面进行resolveInstanceMethod

这里其实又是isa的走位图,元类的最终指向是NSObject ,类的最终指向也是NSObject,所以我们可以建一个NSObject分类,将对象方法和类方法的动态决议都放在NSObject里面,如下图:

NSObject分类

这样的话就非常的便利了,然后再封装一个SDK,所有的方法报错都可以在这里面得到处理。

但是这样的话有可能其它类的动态方法决议写在了他自己的分类里面,会搞的很乱。 所以接下来进入我们的主角,用消息转发来处理崩溃。

消息转发

在动态方法决议完了之后还没找到imp,会来到消息转发,但是我们找了半天,也没找不到消息转发相关的源码。走在金字塔顶端的人永远是少数, 这里的话一般人又玩不了了,那么怎么办呢, 有两种方法:

1、通过instrumentObjcMessageSends方式打印发送消息的日志

2、通过Hopper或者IDA反编译的方式(Hopper要钱,IDA不要钱,但要在windows下运行才稳定)

首先我们来看instrumentObjcMessageSends

logMessageSend
instrumentObjcMessageSends

从源码中我们可以看出里面有一个控制开关,根据objcMsgLogEnabled是否打开来判断是否调用logMessageSend打印日志,接下来我们就调用instrumentObjcMessageSendsobjcMsgLogEnabled设置成YES,设置成YES之后就会来到logMessageSend打印日志

由于instrumentObjcMessageSends是内部的方法,在外面无法直接调用,所以我们用extern让它被外界知道,然后将sayHello包起来

调用instrumentObjcMessageSends

包起来之后运行代码,运行完了之后,我们根据logMessageSend里面的/tmp/msgSends路径来到msgSends,发现msgSends下有一个 msgSends-2376,这个里面就是打印的日志信息,我们打开来看一下

msgSends里面日志信息

看到这里,整个崩溃前的调用流程我想大家都清楚了,我怕有的人还不清楚,我再截个图注释一下。这个地方说明一下,在慢速转发签名之后还会调用一次resolveInstanceMethod,系统给了一次不让漂流瓶流出去的机会。所以加上签名之后的一次,resolveInstanceMethod总共会来两次。如果在签名之前把消息处理了就只会来一次

msgSends注释

我们先来看看消息快速转发,官方的解释是如果这个消息没有人接收的时候,返回它的第一继承人去实现,比如我在forwardingTargetForSelector返回[LGStudent alloc]LGStudent里面定义了sayHello,运行,结果就不报错了,这就是牛逼的消息快速转发流程

forwardingTargetForSelector消息快速转发

再来看看我们的消息慢速转发流程,需要注意的是,慢速转发需要返回一个消息签名,不能返回空,签名如果返回空就会报错。然后根据官方文档的解释再调用forwardInvocation将消息抛出去给其他对象

官网methodSignatureForSelector

看完官方文档之后我们用代码来进行慢速查找一下

methodSignatureForSelector 消息慢速转发

没有崩溃,非常的完美, 那么anInvocation究竟是什么玩意呢,我们点开来看一下

NSInvocation

发现anInvocation里面的有方法的信息,那么为什么没有崩溃了呢,其实就是把anInvocation这个事务抛出去了,就跟漂流瓶一样。 同时我们还可以将这个事务保存下来,以便知道方法崩溃的信息,所以慢速转发更加灵活,更加舒服。

所以整个的消息流程就如下面这幅图:

消息转发流程图

接下来我们再通过反编译的方式来查看流程

这里需要用一个工具Hopper,这个工具可以将我们可执行文件反汇编成伪代码、控制流程图等

我们把程序运行崩溃,然后查看堆栈信息,发现___forwarding___来自CoreFoundation

程序崩溃堆栈信息

但是我们怎么找都找不到CoreFoundation的源码, 苹果闭源了, 所以这时候我们就要用到Hopper通过反汇编来查看。

我们通过image list读取镜像找到CoreFoundation文件路径,然后找到可执行文件

CoreFoundation

找到可执行文件后,打开hopper,选择Try the Demo,然后将可执行文件拖入hopper进行反汇编,选择x86(64 bits),拖进去之后神奇的一幕就发生了,我们将CoreFoundation可执行文件进行反汇编了,反汇编之后我们全局搜索__forwarding_prep_0___

全局搜索__forwarding_prep_0___

找到之后我们点进去,点进去之后发现看不懂,看不懂就再点击上面的伪代码按钮,如下图

伪代码按钮

点完伪代码之后,我们再点击____forwarding___,往下看, 会来到forwardingTargetForSelector: 快速转发流程

快速转发

如果快速转发没有响应,或者返回值为空的话,则会跳转至loc_64a67进入慢速转发流程

慢速转发流程
报错信息

在慢速转发过程中,如果没有响应methodSignatureForSelector,则走到loc_64dd7直接报错。如果获取methodSignatureForSelector的方法签名为nil,则走到loc_64e3c里面报错。

如果返回的方法签名不为nil,则会走到forwardInvocation方法中,对invocation事务进行处理,如果不处理也不会报错

forwardInvocation

好了,通过反汇编的形式又将我上面发的那一幅流程图走了一遍,这就是动态方法决议之后进行的消息快速转发消息的慢速转发

iOS 底层原理 文章汇总

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,542评论 6 504
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,822评论 3 394
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 163,912评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,449评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,500评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,370评论 1 302
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,193评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,074评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,505评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,722评论 3 335
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,841评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,569评论 5 345
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,168评论 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,783评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,918评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,962评论 2 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,781评论 2 354