我的思路是这样的:
从问问题的角度来讲,为什么我们会把+load和+initialize这两个方法拿到一起来比较?
那肯定是他们之间肯定既有相似的地方,又有区别
相同点
首先,相同点:
+load和+initialize都是在运行时调用,且都只会调用一次
区别
但是重要的还是他们之间的区别:
1)调用时机不一样
虽然+load和+initialize都是在运行时调用,且都只会调用一次
但不同的是:
+load方法不需要开发人员手动调用,系统会在App启动时的initialize阶段,自动调用;
+initialize方法是在该类第一次使用的时候调用一次;
所以说,+load方法是肯定会调用,+initialize方法不一定会调用;
2)继承
- 针对
+load
当父类和子类都实现+load方法时, 会先调用父类的+load方法, 再调用子类的+load方法
当子类未实现+load方法时,不会调用父类的+load方法
- 针对
+load
当父类和子类都实现+initialize方法时, 先调用父类的+initialize再调用子类的+initialize
当子类未实现+initialize方法时,会把父类的实现继承过来调用一遍,在此之前父类的+initialize方法会被优先调用一次
所以,从继承方面来看,+load和+initialize方法的主要区别,在于当子类为实现对应的方法时,是否会主动先调用父类中对应的方法
3)分类(category)
当在类的分类中实现了+load方法和+initialize方法时
- 该类的每个分类的
+load方法都会调用,且不会覆盖该类本身的+load方法,调用顺序是先加载原始类,再加载分类的+load方法 - 但是,
+initialize方法会发生覆盖效果,具体最后使用哪个分类的+initialize方法,是根据build phase阶段分类的加载顺序决定的,最后加载的分类的+initialize方法会覆盖前面加载分类的+initialize方法
以上,就是+load和+initialize方法的主要区别了。
扩展
你以为到这里就该结束了吗?
too young,too simple
其实,从本质上来讲,导致这两个方法区别的原因是:
+load方法的调用,是系统直接获取到方法的地址,进而调用+load方法。是指针调用;
但是,+initialize方法的调用,是使用RunTime机制的msg_send调用;
因为,系统在App启动时的load阶段,先会注册所有的类,并将分类中的方法插入到方法列表中。而且是插入到方法列表的最前面。
所以,在调用+initialize方法时,通过msg_send方式,会根据isa指针,在元类的方法列表中,从头部开始查找,找到了就返回执行函数实现,没找到则会再根据superclass指针,在其父类中查找。
这样就再一次验证了上面提到的结论(区别)
\