OC底层原理03 - NSObject的alloc 源码分析
本章主要是探索[NSObject alloc]
和[自定义类 alloc]
的源码流程是否一致,如果不一致具体是在哪里发生不同?
分析NSObject的alloc流程
发现问题
-
在main函数是增加一个NSObject对象的定义,并在对象处加上断点。
image.png
当程序运行起来时,停在断点处,即将开始执行[NSObject alloc]。
- 根据自定义类的alloc流程分析,知道第一步应该是进入alloc方法,即在alloc方法处加上断点。
image.png - 执行target,此时发现并未在断点处停下。这是为什么呢?
跟踪NSObject alloc的流程
-
运行target在即将开始执行
[NSObject alloc]
断点停下。 -
按住control+step into,通过汇编跟踪流程,此时汇编显示如下:
image.png -
由图可见,此时是进入了
image.pngobjc_alloc
方法,下“objc_alloc”的符号断点,继续运行target,发现确实是进入了objc_alloc
的源码中。
-
继续进入
image.pngcallAlloc
源码中
-
由于NSObject没有自定义的
allocWithZone
方法,cls->ISA()->hasCustomAWZ()为0
,因此会进入_objc_rootAllocWithZone
方法。
在_objc_rootAllocWithZone
方法中,跟自定义对象的alloc流程一致,完成alloc的重要三步骤:
1. 计算需要开辟的内存空间大小(size = cls->instanceSize(extraBytes);
2. 开辟指定大小的空间(obj = (id)calloc(1, size));
3. 将对象与isa指针关联起来(obj->initInstanceIsa(cls, hasCxxDtor));
至此,NSObject的alloc就完成了。从流程分析中得到,NSObject的alloc确实不会进入到alloc
方法中。
NSObject alloc 的调用流程图
image.pngNSObject alloc与自定义类的alloc区别
上面分析NSObject alloc首先进入的是objc_alloc
方法,那自定义类的alloc会不会进入这个方法呢?
-
在main函数时增加一个自定义类对象的定义,并在定义处增加断点,运行target使其在断点处停下。
image.png - 打开
objc_alloc
的符号断点、alloc
的符号断点。运行target发现断在了objc_alloc
处。
image.png - 进入
callAlloc
,继续往下调试。
image.png
此时cls->ISA()->hasCustomAWZ()为1
,即LGPerson有自定义在alloc方法。于是进入到objc_msgSend
。 - 通过
objc_msgSend
方法发送alloc
的方法编号给当前类。此时进入了alloc
方法中。
image.png - 再继续运行依次是
_objc_rootAlloc
方法,callAlloc
方法,此时在callAlloc
方法中cls->ISA()->hasCustomAWZ())为0
,会进入_objc_rootAllocWithZone
方法。 - 在
_objc_rootAllocWithZone
方法中完成alloc的重要三步骤。
自定义类的alloc调用流程
image.png区别
-
NSObject
是iOS中的基类,所有的自定义类都需要继承NSObject。 -
LGPerson
是继承自NSObject类的,重写了NSObject中的alloc
方法。
总结
[NSObject alloc]
流程与[LGPerson alloc]
流程在cls->ISA()->hasCustomAWZ())
判断前一致,但是由于LGPerson
类重写了NSObject中的alloc
方法,cls->ISA()->hasCustomAWZ())
这个判断的结果与NSObject结果不一样。NSObject类直接去完成alloc
的重要三步骤
,而LGPerson类需要通过sel找到alloc
方法的编号后再执行alloc方法。