本文由快学吧个人写作,以任何方式转载请表明原文出处
一、材料准备
objc4-818.2
对应mac的版别是11.1。可根据自己的系统版别挑选能够进行调试的源码。
二、思路
- 上一章知道了非懒加载类是如何从一个镜像中加载到了内存中并且被完成,从而真实的被app运用到。
- 那懒加载的类呢?
三、懒加载类的加载完成
1. 懒加载类和非懒加载类的差异
懒加载类 : 在第一次调用的时分才完结完成和加载。
非懒加载类 : 在程序初始化的时分就进行了加载。
例如 : 在一个类的完成中写入一个+(void)load办法,哪怕+(void)load中什么都不写,这个类也会变成非懒加载类。
2. 懒加载类的完成
1. 创立一个懒加载类
既然懒加载类没有在最开始的程序初始化时进行加载,而是在第一次调用的时分完结加载,那么能够举例 :
- 在objc818.2中创立一个
JDMan
类,承继于NSObject
。增加一些实例变量、属性和办法,可是不要在JDMan.m
中写入+(void)load
办法。
- 现在的
JDMan
是懒加载的,能够验证。进入到_objc_init(void)
—>map_images
—>map_images_nolock
—>_read_images
。找到非懒加载类的完成的for循环。在其中参加如下代码,获取mach-o静态段中保存的所有的非懒加载类 :
执行代码,会获得到mach-o中的非懒加载字段中的所有非懒加载类,在lldb中查找:JDMan,是找不到的 :
证明JDMan不在可执行文件的非懒加载的表中,所以JDMan是懒加载类。
2. 懒加载类的完成
- 在
main.m
文件中实例化一个JDMan
的实例 :
-
当
JDMan
这个懒加载类调用到alloc
这个办法的时分,就是JDMan
在被运用了,那么JDMan
就需要被完成。 -
JDMan
调用alloc办法的实质是objc_magSend
,这个之前说办法的实质的时分说过。既然是objc_msgSend
,那么就会进行缓存查找或lookUpImpOrForward
,JDMan
是第一次被运用,所以缓存中必然是不存在alloc
办法的缓存的,那么就会找到lookUpImpOrForward
。 -
lookUpImpOrForward
中是有检查类是否完成的,进入lookUpImpOrForward
源码,如下图 :
-
可是,这里有一个问题,
[JDMan alloc]
这个是类在调用类办法,那么lookUpImpOrForward
中的cls应该是JDMan
元类,inst
才是JDMan
类。 -
先进入
realizeAndInitializeIfNeeded_locked
源码 :
- 一步一步的进入
initializeAndLeaveLocked
:
- 上面那一步注意,第一个参数传的是
nonmeta
,是JDMan
类。一步一步的进入realizeClassMaybeSwiftAndUnlock
:
3. 懒加载类的加载的定论 :
懒加载类是通过lookUpImpOrForward进入到的
realizeClassWithoutSwift
,在上一章已经说过realizeClassWithoutSwift
是怎样完成一个类的,不再重复。