iOS底层探究-04:NSObject的alloc源码分析

在上篇文章我们探究了自定义类alloc源码,接下来我们探究下NSObjectalloc源码,我们会发现她并不会走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的源码,此时查看 clsNSObject

NSObject 为什么走 objc_alloc ?

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

  • NSObject是iOS中的基类,所有自定义的类都需要继承自NSObject

  • LCPerson继承NSObject类的,重写NSObject中的alloc方法
    然后根据之前汇编的显示,可以看出,NSObjectLCPerson都调用了objc_alloc,就有以下两个疑问

  • 为什么NSObject调用alloc方法 会走到 objc_alloc 源码?

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

LCPerson中alloc 走两次 的 Why?

我们在源码中调试,在mainLCPerson加断点运行程序,再在allocobjc_alloccallAlloc 源码加断点,继续运行,发现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的源码工程中

你可能感兴趣的:(iOS底层探究-04:NSObject的alloc源码分析)