在上篇文章我们探究了自定义类
的alloc
源码,接下来我们探究下NSObject
的alloc
源码,我们会发现她并不会走alloc
的源码工程 Why ???这就是我们要探究的
我们在可编译源码中的main函数中创建一个NSObject
的对象和一个自定义
的对象,同时添加断点,如下所示:
运行工程,当断点断在NSObject *obj = [NSObject alloc]
在alloc
源码处添加断点,继续运行
我们会发现断点并没有断在alloc
的源码处,而是直接断到了LCPerson *p1 = [LCPerson alloc]
这里,也就是说[NSObject alloc]
并没有走alloc
的源码
接下来我们开启汇编调试:Debug --> Debug Workflow --> 勾选 Always Show Disassemly
,只保留mian
函数中的断点,其他均关闭或删除,运行工程,通过汇编可以发现NSObject
并没有走 alloc
源码,而是走的objc_alloc
然后关闭汇编调试,在全局搜索 objc_alloc
,在objc_alloc
中加一个断点,先暂时关闭
运行程序,断点断在NSObject *obj = [NSObject alloc]
打开objc_alloc
处的断点,继续执行,发现会进入objc_alloc
的源码,此时查看 cls
是 NSObject
NSObject 为什么走 objc_alloc ?
首先,我们来看看 NSObject 与 LCPerson的区别
NSObject
是iOS中的基类
,所有自定义的类都需要继承自NSObjectLCPerson
是继承
自NSObject
类的,重写
了NSObject
中的alloc
方法
然后根据之前汇编的显示,可以看出,NSObject
和LCPerson
都调用了objc_alloc
,就有以下两个疑问
:为什么
NSObject
调用alloc
方法 会走到objc_alloc
源码?为什么
LCPerson
中的alloc
会走两次
?即调用了alloc
,进入源码,然后还要走到objc_alloc
?
LCPerson中alloc 走两次 的 Why?
我们在源码中调试,在main
中LCPerson
加断点运行程序,再在alloc
、 objc_alloc
和 callAlloc
源码加断点,继续运行,发现LCPerson 第一次的alloc
会走到 objc_alloc --> callAlloc
方法中最下方的objc_msgSend
,表示向系统发送消息
继续执行,会走到 alloc --> callAlloc --> _objc_rootAllocWithZOne
,也就是iOS底层探究-03:alloc & init & new 源码分析中的alloc流程
由上述调试过程可以得出,LCPerson
走两次
的原因是首先需要去查找sel
,以及对应的imp
的关系,当前需要查找的是 alloc
的方法编号,但是为什么会找到objc_alloc
?这个就需要问系统了,肯定是系统在底层做了一些操作,请继续往下看
NSObject 中 alloc 走到 objc_alloc 的 why ?
这部分需要通过 LLVM源码
(即 llvm-project
) 来分析
- 在llvm源码中搜索
objc_alloc
,未找到
- 搜索
tryEmitSpecializedAllocInit
,非常著名的特殊消息发送,在这里也没有找到objc_alloc
- 开启上帝视角,通过
alloc
字符串搜索,如果还找不到,还可以通过omf_alloc:
找到tryGenerateSpecializedMessageSend
,表示尝试生成特殊消息发送
在这里可以找到调用alloc
,转而调用了EmitObjCAlloc
处理了objc_objc
的逻辑,代码如下:
由此可以得出 NSObject
中的alloc
会走到 objc_alloc
,其实这部分是由系统级别的消息处理逻辑
,所以NSObject的初始化是由系统完成的,因此也不会走到alloc的源码工程中