+load和+initialize方法的区别是什么?

183 阅读3分钟

我的思路是这样的:

从问问题的角度来讲,为什么我们会把+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指针,在其父类中查找。

这样就再一次验证了上面提到的结论(区别)


\