load
在联想到viewDidLoad等方法时很容易在内心中萌生一种错误的想法,在参考了1个帖子后终于对load方法有了一个大概的理解
1.load函数的加载时机
简单来说load方法是在这个文件被程序装载时调用,因此load方法是在main方法调用前调用
2.load方法调用的顺序
superClass -> class -> category
3.load方法的作用和使用场景
由于load的调用时机比较早,通常是在App启动加载的时候开始,这时候并不能保证所有的类都被加载完成并且可以使用。并且load加载自身也存在不确定性,因为在有依赖关系的两个库中,被依赖的类的load方法会先调用,但是在一个库之内调用的顺序是不确定的。除此之外,load方法是线程安全的,因为内部实现加上了锁,但是也带来了一定的性能开销,所以不适合处理很复杂的事情。一般,会在load方法实现Method Swizzle(方法交换实现)。
load方法是直接使用函数指针调用,也就是走C语言函数调用的流程,不是发送消息,并不会走消息转发的流程,也就是说,如果一个类实现了load函数就会调用,如果没有实现也不会调用该类的父类load函数实现,如果父类实现了load函数的话。category调用load方法也是一样的道理。
initialize
1.initialize函数的加载时机
这个函数是懒加载,只有当类接收了第一个消息的时候才会调用initialize函数,否则一直不会调用。
2.initialize函数的调用顺序
initialize函数的调用顺序为:superClass -> class。这里没有分类,因为一个类的initialize函数只会调用一次,如果需要实现独立的class和category的初始化就需要实现load函数。还需要注意的一点就是,如果subClass没有实现initialize函数,则父类的initialize函数会被调用两次
由于initialize函数可能会被调用多次,所以,如果想保证initialize函数只被调用一次,苹果建议这样做:
+(void)initialize {
if (self == [className self]) { // ... do the initialization ... }
}
3.initialize函数的使用场景
initialize是线程安全的,有可能阻塞线程,所以,initialize函数应该限制做一些简单,不复杂的类初始化的前期准备工作。
initialize函数的工作相当简单,就是发送消息,这是和load函数实现不一样的地方,load函数的调用直接是函数指针的调用,而initialize函数是消息的转发。所以,class的子类就算没有实现initialize函数,也会调用父类的initialize函数,如果子类实现了initialize函数,则子类不会调用父类的initialize函数。
总结
1.load在被添加到runtime的时候加载,initialize是类第一次收到消息的时候被加载,load是在main函数之前,initialize是在main函数之后。
2.load方法的调用顺序是:superClass -> class -> category;initialize方法的调用顺序是:superClass -> class。都不需要显示调用父类的方法,系统会自动调用,load方法是函数指针调用,initialize是发送消息。子类如果没有实现load函数,子类是不会调用父类的load函数的,但是子类没有实现initialize函数,则会调用父类的initialize函数。
3.load和initialize内部实现都加了线程锁,是线程安全的,因此,这两个函数应该做一些简单的工作,不适合复杂的工作。
4.load函数通常用来进行Method Swizzle,initialize函数则通常初始化一些全局变量,静态变量。