注册
iOS

iOS-底层原理 04:NSObject的alloc 源码分析

主要NSObject中的alloc是与自定义类的alloc源码流程的区别,以及为什么NSObject中的alloc不走源码工程。

上一篇文章中分析了alloc的源码,这篇文章是作为对上一篇文章的补充,去探索为什么NSObject的alloc方法不走源码工程。

NSObject的alloc无法进入源码的问题

首先在objc4-781可编译源码中的main函数中增加一个NSObject定义的对象,NSObject 和 LGPersong同时加上断点

68228bf88a9c5049cd150416f05f4322.png


alloc的源码实现中加一个断点,同时需要暂时关闭断点

c512c2671653bf7c970e55f46ec1bc06.png

运行target,断点断在NSObject部分,打开alloc源码的断点,然后继续执行,会出现以下这种现象

611836bf31402138a96574343db726a2.gif

探索Why

【第一步】探索[NSObject alloc]走的是哪步源码

接下来,我们就来探索为什么NSObject的alloc会出现这种情况,首先,

  • 打开Debug --> Debug Workflow --> 勾选 Always Show Disassemly,开启汇编调试

    关闭源码的断点,只留main中的断点,重新运行程序,然后通过下图的汇编可以发现NSObject并没有走 alloc源码,而是走的objc_alloc

52647049bf34b6326ca5e09664cb0698.png

然后关闭汇编调试,在全局搜索 objc_alloc,在objc_alloc中加一个断点,先暂时关闭,

07e77a26cf22e4d97f3bd066470bf7a5.png

重新运行进行调试,断住,然后打开objc_alloc的断点,发现会进入objc_alloc的源码实现,此时查看 cls 是 NSObject

bdd8815b5e637dc0acc2fad9bb93ca33.png

【第二步】探索 NSObject 为什么走 objc_alloc?

首先,我们来看看 NSObject 与 LGPerson的区别

  • NSObject 是iOS中的基类,所有自定义的类都需要继承自NSObject
  • LGPerson 是继承NSObject类的,重写NSObject中的alloc方法

然后根据第一步中汇编的显示,可以看出,NSObject 和 LGPerson 都调用了objc_alloc,所以这里就有两个疑问

  • 为什么NSObject 调用alloc方法 会走到 objc_alloc 源码?
  • 为什么LGPerson中的alloc 会走两次?即调用了alloc,进入源码,然后还要走到 objc_alloc

LGPerson中alloc 走两次 的 Why?

首先,需要在源码中调试,在mainLGPerson加断点,断在LGPerson,再在alloc 、 objc_alloc 和 calloc 源码加断点,运行demo,会断在objc_alloc源码中(重新运行前需要暂时关闭源码中的所有断点)

4ea209f758b38a705906732d0371cd47.png

继续运行,发现LGPerson 第一次的alloc会走到 objc_alloc --> callAlloc方法中最下方的objc_msgSend,表示向系统发送消息

71ed0893941aa4397f8123808a8bb4c8.png

5d9acd9d6e7fc7388dca984debb0c1d3.png

所以由上述调试过程可以得出,LGPerson两次的原因是首先需要去查找sel,以及对应的imp的关系,当前需要查找的是 alloc的方法编号,但是为什么会找到objc_alloc?这个就需要问系统了,肯定是系统在底层做了一些操作。请接着往下看

NSObject中alloc 走到 objc_alloc 的 why?

这部分需要通过 LLVM源码(即llvm-project) 来分析

准备工作:首先需要一份llvm源码

在llvm源码中搜索objc_alloc

b1ee9c8c8dfaa179930beee561c1751b.png

搜索shouldUseRuntimeFunctionForCombinedAllocInit,表示版本控制

dd4c5bb5f1e3bd093642153e6b343803.png

搜索tryEmitSpecializedAllocInit,非常著名的特殊消息发送,在这里也没有找到 objc_alloc

5f9ddf54347ea925f07f559ca1010517.png

继续尝试,开启上帝视角,通过alloc字符串搜索,如果还找不到,还可以通过omf_alloc:找到tryGenerateSpecializedMessageSend,表示尝试生成特殊消息发送

1c5a9a017e5353cd03b28a33c27adcbc.png

然后在这个case中可以找到调用alloc,转而调用了objc_objc的逻辑,其中的关键代码是EmitObjCAlloc

7d2e55bca1e191a5346c955fef46316b.png

跳转至EmitObjCAlloc的定义可以看到alloc 的处理是调用了 objc_alloc

cec6387ae2f485f020ea378f679c8172.png

由此可以得出 NSObject中的alloc 会走到 objc_alloc,其实这部分是由系统级别的消息处理逻辑,所以NSObject的初始化是由系统完成的,因此也不会走到alloc的源码工程中

总结

总结下NSObject中alloc 和自定义类中alloc的调用流程

NSObject

bb08dd3c26017042dc331384fa647aab.png

自定义类

6661bf79aa954c533bb1f6d399552126.png

作者:style_月月
链接:https://blog.csdn.net/lin1109221208/article/details/108480971

著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

0 个评论

要回复文章请先登录注册