initialize - ShenYj/ShenYj.github.io GitHub Wiki
initialize
方法是在类或它的子类收到第一条消息之前被调用的,这里所指的消息包括实例方法和类方法的调用。也就是说 initialize
方法是以懒加载的方式被调用的,如果程序一直没有给某个类或它的子类发送消息,那么这个类的 initialize
方法是永远不会被调用的。那这样设计有什么好处呢?好处是显而易见的,那就是节省系统资源,避免浪费。
runtime 使用了发送消息 objc_msgSend
的方式对 initialize
方法进行调用。也就是说 initialize
方法的调用与普通方法的调用是一样的,走的都是发送消息的流程。换言之,如果子类没有实现 initialize
方法,那么继承自父类的实现会被调用;如果一个类的分类实现了 initialize
方法,那么就会对这个类中的实现造成覆盖。
-
调用时机:
-
类在第一次接到的消息的时候调用,每一个类只会
initialize
一次如:
[Person alloc]
,就会调用一次,并且后面再alloc
也不会调用
-
-
调用顺序:
- 先调用父类的
initialize
- 再调用原类的
initialize
- 如果原类有分类,并且分类重写
initialize
,则会调用分类中的initialize
(按着编译的反顺序,越后编译越先被执行, 源码的处理方式是插入到方法列表的前部) - 当子类没有
initialize
,会调用父类的initialize
,父类可能被调用多次 -
e.g. 父类Person,实现
initialize
,两个子类 Student、Teacher,分别继承自Person,未实现initialize
当初始化Student、Teacher后就会发现 Person的initialize
被调用了三次- 当类第一次收到消息时,首先会优先检查当前类(这里指子类)是否初始化,没有初始化在对当前类发送
initialize
消息前,递归检查父类有没有初始化(处理过程与load有些相似,不过load
是方法地址直接调用),此时 Person 肯定也没有初始化,因此会执行两次 msgSend,分别是 Person 和 子类(假设为Student) - 另外一个子类也会做同样的检查,但是此刻Person已经被标记为初始化,因此只有一次msgSend -> 当前子类(假设为Teacher)
- 由于
initialize
走的是消息发送机制,通过isa找到元类对象发现自己没实现initialize
,会顺着superclass向上查找,找到父类Person,所以三次msgSend都触发了父类initialize
被调用
- 当类第一次收到消息时,首先会优先检查当前类(这里指子类)是否初始化,没有初始化在对当前类发送
- 如果原类有分类,并且分类重写
- 先调用父类的
-
initialize
方法调用流程lookUpImpOrForward -> realizeAndInitializeIfNeeded_locked -> initializeAndLeaveLocked -> initializeAndMaybeRelock -> initializeNonMetaClass -> callInitialize -> initialize
initialize
方法在第一次消息发送的时候才调用,所以并不会影响类和分类的加载情况