本文由快学吧个人写作,以任何方式转载请标明原文出处

一、预备资料

objc4-818.2

对应mac的版别是11.1。可根据自己的系统版别挑选能够进行调试的源码

二、思路

  1. 无论是上一章还是本章,都是对十三章lookUpImpOrForward的一个完善。
  2. 动态办法抉择之后,lookUpImpOrForward还有一个流程是 :日志和增加缓存
  3. 那么关于办法查找的日志中都会有一些什么?

三、项目预备

  1. 为了日志中没有其他因素的搅扰,所以创立一个新的mac项目。

  2. 创立一个新的mac项目,并在其中创立一个JDMan类和一个JDKid类,都继承于NSObject。

  3. 然后在JDMan.h中增加一个实例办法,而且不完成这个实例办法。然后在main.m中实例化一个JDMan的实例,并让实例调用这个实例办法。如下图 :

十五、浅谈消息转发

十五、浅谈消息转发

四、怎么找到lookUpImpOrForward的日志

  1. 在818.2的源码中,找到lookUpImpOrForward的源码。找到done: 中的日志和缓存增加的源码。

十五、浅谈消息转发

  1. 进入log_and_fill_cache源码,如下 :

十五、浅谈消息转发

  1. 发现一个宏判别和一个判别条件。

(1). 宏判别的条件SUPPORT_MESSAGE_LOGGING!TARGET_OS_OSX的条件下为0,由于我创立的是mac项目,所以!TARGET_OS_OSX == 0。则SUPPORT_MESSAGE_LOGGING == 1。所以会进入if判别。

(2). objcMsgLogEnabled在源码中找到默认是false。

  1. if判别中的logMessageSend源码 :

十五、浅谈消息转发

  1. 找到了日志存储的途径。先直接运转上面预备的项目,然后用Finder进入这个途径,检查/tmp目录下是否有msgSends前缀的日志文件。成果会发现没有。也就是说,objcMsgLogEnabled在默认为false的情况下,是不会生成日志的,那么假如让objcMsgLogEnabled为true,是否会生成日志?

  2. 怎么让objcMsgLogEnabled为true。肯定不能直接在源码中修改。所以查找objcMsgLogEnabled,发现如下函数能够为它赋值 :

十五、浅谈消息转发

  1. 在上面创立的项目中,在main.m中,为instrumentObjcMessageSends函数做一个外部声明进行扩充,让我们能够调用它。并将main.m代码改成如下 :

十五、浅谈消息转发

  1. 运转项目,项目会溃散,由于未完成ceShi办法,这个无所谓。然后进入/tmp途径下,找到日志文件,翻开日志 :

十五、浅谈消息转发

十五、浅谈消息转发

  1. 会发现在resolveInstanceMethod动态办法抉择之后,办法的查找流程还会调用两个函数 :

forwardingTargetForSelectormethodSignatureForSelector。这个就是所谓的音讯转发。

五、forwardingTargetForSelector:

  1. 详细信息能够找xcode供给的官方Help文档(command + shift + 0(零)),查找forwardingTargetForSelector。这儿不做详细展现。

(1). 回来值id : 想要哪个目标处理未完成的办法,就回来哪个目标。

(2). 参数aSelector : 未完成的办法的SEL。

  1. 在818.2源码中查找forwardingTargetForSelector,发现是有两个办法的,一个类办法,一个实例办法 :

十五、浅谈消息转发

  1. 举例 :

(1). 运用上面创立的项目。再给JDMan增加一个类办法,而且同样不在JDMan中进行完成。

十五、浅谈消息转发

(2). 在JDMan.m中完成forwardingTargetForSelector的类办法和实例办法。

十五、浅谈消息转发

(3). 既然转发给了JDKid,那么在JDKid.m中完成(1)图中的两个JDMan的办法。

十五、浅谈消息转发

(4). 运转代码 :

十五、浅谈消息转发

(5). 实例办法就用实例办法的forwardingTargetForSelector进行转发。 类办法则就用类办法的forwardingTargetForSelector进行转发。类办法不要用实例办法的,实例办法也不要用类办法的forwardingTargetForSelector

六、methodSignatureForSelector:

  1. 详细信息能够找xcode供给的官方Help文档(command + shift + 0(零)),查找methodSignatureForSelector。这儿不做详细展现。

(1). 回来值NSMethodSignature : 办法的encodingType,也就是办法的编码类型,包含办法的回来值和参数的类型信息。

(2). 参数aSelector : 未完成的办法的SEL。

  1. NSMethodSignature的初始化办法也能够在Help文档中找到 :

十五、浅谈消息转发

  1. methodSignatureForSelector需求调配forwardInvocation办法一同运用。

  2. 举例 :

(1). 运用上面举例中的项目,不完成forwardingTargetForSelector。JDMan.m中代码 :

十五、浅谈消息转发

(2). 运转成果

十五、浅谈消息转发

(3). 实例就用实例的办法,类就用类办法的。

  1. 能够只完成methodSignatureForSelector,不完成forwardInvocation中的代码,就是forwardInvocation要写出来,可是内部不写任何东西,也不会溃散。

十五、浅谈消息转发

十五、浅谈消息转发

七、总结

音讯转发有两种办法 :

  1. forwardingTargetForSelector,有实例办法和类办法,能够回来一个对未完成办法进行完成的目标或者类,这个目标或者类内部假如完成了这个未完成的办法,则不会报错。

  2. methodSignatureForSelector,有实例办法和类办法,会回来一个NSMethodSignature目标。相当于把未完成办法的encodingType(办法类型编码)存放到进程的调度中心里。等待着其他完成者来完成。

  3. methodSignatureForSelectorforwardInvocation调配运用。能够不在forwardInvocation内写代码。可是必须要写出来forwardInvocation这个办法。