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

一、思路

在找目标的实质和类的实质的时分,是经过clang将.m文件编译成了c++的.cpp文件,检查编译后的代码,找到了目标的实质是结构体,类的实质是结构体objc_class : objc_object。

那么办法的实质也能够经过clang来检查。

二、创立项目

创立一个macos下的项目,便于测验。

  1. 创立一个类(我创立的是JDMan)继承于NSObject,并在JDMan中添加实例办法和类办法。
  2. 另外在main.m中引入runtime的头文件:<objc/message.h>
  3. 在main.m中创立一个JDMan的实例变量,并让这个实例变量调用实例办法。

创立概况如下 :

十一、方法的本质

十一、方法的本质

三、编译main.m

用terminal(终端)进入项目所在的文件夹再运用clang指令 :

clang -rewrite-objc main.m -o main.cpp

得到main.cpp文件,翻开它。

十一、方法的本质

直接查找自界说的实例办法,找到main函数里面 :

十一、方法的本质

四、办法的实质是否是objc_msgSend

第四节的图中看到alloc和zhuanQian两个办法中的共同点都是调用了objc_msgSend函数。那么objc_msgSend是否真的是办法的实质?验证一下是否正确。

思路 :

  1. 不调用任何的办法。只调用objc_msgSend。
  2. 假如办法的实现仍然被调用了,那么就证明办法的实质便是objc_msgSend

1. objc_msgSend的参数

想调用objc_msgSend,就要知道它需求什么参数,在进入objc_msgSend(找到

十一、方法的本质

所以一个参数是:id self一个是SEL op。也便是说,一个是接收者,一个是办法索引SEL。

2. 只调用objc_msgSend发送信息

  1. 代码如下 :

十一、方法的本质

发现run起来会报错 : Too many arguments to function call, expected 0, have 2

原因是没有封闭objc_msgSend的严格检查。

  1. 封闭objc_msgSend的严格检查 :

十一、方法的本质

为什么要封闭这个检查?

因为objc_msgSend归于runtime的函数,自身是一个动态办法,中间会有许多的参数出现,假如想要静态的编译它,像C语言的函数相同,那就需求封闭检查。

  1. 正常运行

十一、方法的本质

这就能够证明实例办法的实质便是objc_msgSend音讯发送。那么类办法呢?

五、类办法的实质是否相同

  1. 让类发送音讯,经过objc_msgSend验证

十一、方法的本质

成果 :

十一、方法的本质

  1. 让类调用类办法,经过clang取得编译后的文件,检查类办法的调用的实质

用terminal(终端)进入项目所在的文件夹再运用clang指令 :

clang -rewrite-objc main.m -o main.cpp

得到main.cpp文件,翻开它。

十一、方法的本质

结论是相同的 :

办法的实质便是objc_msgSend发送音讯。

六、扩展一下

1. objc_msgSendSuper

objc_msgSend还有一个函数 : objc_msgSendSuper(),是子类调用父类的办法。

看一下objc_msgSendSuper的参数 :

十一、方法的本质

参数是struct objc_super *SEL

需求找开源源码818中去查找struct objc_super是什么。

十一、方法的本质

2. 项目更改

在原项目上再创立一个JDKid类,继承于JDMan。不界说任何的办法。

3. 子类调用父类的实例办法

十一、方法的本质

成果 :

十一、方法的本质

4. 子类调用父类的类办法

十一、方法的本质

成果 :

十一、方法的本质

5. 特殊情况

十一、方法的本质

成果 :

十一、方法的本质

为什么?

原因很简单 :isa的神图。一句话,自己没有找爹要。

十一、方法的本质

七、总结

办法的实质便是objc_msgSend音讯发送。