iOS 探讨之 ObjC类初始化

阐述
近期发现iOS黑魔法中许多神奇的操作都是在类初始化的时候,之前玩的方式都是在对象实例化的时候,感觉发现了一片新大陆玩耍一下。

探讨
NSObject 作为大多数类的基类(NSProxy特殊)我们首先去IDE中寻求与类初始化有关的信息。


在NSObject 的介绍信息中,关于类初始化这方面官方提到了两个方法: + initialize、 + load 。
也就是说我们可以在这两个方法中搞一些有"意思"的事情。

+ load

官方在开篇直接指出: 
类文件或类幕文件在加入到runtime(个人理解为应用运行时,编译、链接之后的阶段)时,该类文件或类幕文件的 + load 方法会被调用。
注意: 只有实现了 + load 方法的类文件或类幕文件在类加载时才会被调用。
↓↓↓ 官方标注 ↓↓↓

复杂应用文件间类初始化顺序:(都符合 + load 调用的条件)
1 开发者引用的框架中的文件
2 开发者编写的OC文件
3 所有C++静态初始化文件和C/C++  __attribute__(constructor) 声明的函数
4 其它引用开发者编写文件的框架

类系文件(子类、父类、类幕)的类初始化顺序:
1 先初始化所有父类,再初始化子类
2 所有类幕文件在所有类初始化完后初始化
3 每个类文件中的 + load 方法只会执行一次
4 在以上条件下,在Build Phases - Compile Sources 顺序越靠上初始化越早

Tip:
多个Category里都实现了 + load 方法,那么这些方法都会被调用一次。这个特性决定了+load是干坏事的绝佳场所,比如 swizzling。

+ initialize

官方用简短的一句对 initializes 进行介绍:
在类接收第一条信息的时候对其进行初始化。

应用文件间类初始化的顺序:
1 与类接收到消息的先后有关

类系文件(子类、父类、类幕)的类初始化顺序
1 先初始化父类,再初始化子类
2 若有类幕文件只会初始化类幕文件,不会初始化当前类文件
3 类幕文件只会初始化一个,并且是在Build Phases - Compile Sources 顺序越靠下的文件
4 每个类只会初始化一次(父类 + initialize 有可能会被多次调用)


父类 + initialize 被调多次场景:
1 子类没有实现 initialize 方法
2 子类实现了 initialize 方法,且在实现中执行了 [super initialize] 语句

阻止父类 + initialize 方法执行多次方法:

+ load 与 + initialize 对比:
1 + load 方法会在Class被加载的时候调用,这个时间很早,所有对于需要很早被执行的代码来说是很有用的。
注意:这个时候整体环境尚未初始化完成,调用代码可能出错.
2 + initialize 方法lazy触发,对于初始化设置的环境友好很多。只要不是在类接收第一条消息之前一定要做的事情,都可以在这个方法里面处理。
注意:因为 initialize 是以阻塞的形式执行,故需要限制 initialize 中的任务数量。并且不要在任务中添加锁(Lock),防止死循环的产生。

资料

猜你喜欢

转载自blog.csdn.net/yanglei3kyou/article/details/79395721
今日推荐