要研究objc_msgSend
实现原理,我们就需要在源码中找实现,全局搜索objc_msgSend
。因为有好多架构实现,而真机架构arm64
,所以就看objc-msg-arm64.s
文件里面的实现即可。
代码解释起来比较麻烦,索性画了一张objc_msgSend
的流程图,每一步代码以及代码含义在流程图都有体现:
流程图每一步有序号,序号后面是源码,源码下面是对该行源码的解释,如果看源码流程比较乱,再总结个逻辑流程图:
objc_msgSend逻辑流程图.jpg这个逻辑有个小细节,就是从buckets
里面取元素的时候,如果是nil
,跳出循环直接走__objc_msgSend_uncached
这个方法,为什么有这个判断呢,因为如果按hash
函数算出下标对应位置是空的,或者减减循环找到空位置,那么这个方法一定没有缓存过,所以可以跳出缓存查找逻辑。
lookupImpOrForward
是方法慢速查找流程,那么为什么缓存查找要用汇编实现,方法查找用C++呢?
汇编更接近机器语言,执行起来会非常快,而且汇非常安全,像C语言C++方法的参数都是确定的,而汇编可以动态化一些。我们使用方法缓存就是为了更快找到方法,缓存找不到需要从类遍历查找方法,而遍历是一个慢速过程,所以缓存用汇编实现,方法遍历用C++。
真机验证
说了那么多,都是理论,我们还是要真机验证一下。
SJPerson *p = [SJPerson alloc];
[p say1];
在say1
位置打断点进入真机汇编。
我们可以看到真机汇编流程和我们分析源码基本一致,没得问题,下一篇我们分析方法查找流程。
网友评论