load和initialize
首先先了解一下类的加载和使用:
- 首先当启动app时,程序通过+load方法加载类到内存中(代码区) ;
- 当首次使用该类的时候才会调用+ (void)initlize ;
- 通过类对象创建实例对象的时候+ (instancetype)alloc, - (instancetype)init;
- 通过实例对象,我们就可使用实例方法和属性了 ;
+ (void)load类方法
当类被引用进项目的时候会执行load函数,和它是否被使用无关,在app启动流程中我们也知道了load函数的执行在main函数开始执行之前 ;
每个类的load函数只会调用一次 ;
load函数是系统自动加载的,因此不需要再调用[super load],否则父类的load函数会多次执行 ;
注意的点:
- 当父类和子类都实现load函数时,父类的load方法的执行顺序要优于子类,同时也说明了子类实现load方法不会覆盖父类的实现 ;
- 当一个类未实现load方法时,不会调用父类load方法
- 类的load方法执行顺序要优先于类别 (catgory)
- 当有多个类别(catgory)都实现了load方法,这几个load方法都会执行,但执行顺序不确定;这些
load
方法的执行顺序通常与类别在编译源文件的顺序有关。 - 当有多个不同的类时,每个类load执行顺序与其在编译源文件的顺序有关,也就是说顺序是确定的 ;这和类和类别的加载时机和方式有关 ;
+initialize类方法
- 即是类文件被引用进项目,但没有使用,initliza不会被调用 ;
- 假如这个类放到代码中,而这段代码并没有被执行,这个函数也不会执行的 ;
- 类或者其子类的第一个方法被调用前调用 ;
- 由于是系统自动调用,也不需要再调用[super initliza],否则父类的initliza会被多次执行 ;
- 父类的initliza方法会比子类先执行 ;
- 子类未实现initliza方法时,会调用父类的initliza方法,子类实现initliza方法时,会覆盖父类的initliza方法 ;
- 当有多个catgory都实现了initliza方法,会覆盖类中的方法,只执行一个 (会执行编译源文件中最后一个Category 的initialize方法)
两者的异同
相同点
- load和initlize会被自动调用,不能手动调用
- 如果父类和子类都被调用,父类的调用一定在子类之前 ;
- 子类实现了load和initlize的话,会隐式的调用父类的load和initlize方法 ;
- load和initlize方法内部都使用了锁,是线程安全的 ;
不同点
- 调用顺序不同,以main函数为分界,+load方法在main函数之前执行,+initlize在main ()函数之后执行 ;
- 子类没有实现+load方法的话,不会调用父类的+load方法;而子类即使没有实现+initlize的话,也会调用父类的initlize方法 ;
- +load方法是在类被引用进项目的时候调用,+initlize是在第一次给类发送消息时调用;这里也是单例模式那时提到的懒加载的关键 ;
使用场景
+load一般是用来交换方法Method Swizzle,由于它是线程安全的,而且一定会调用且只会调用一次
+initialize方法主要用来对一些不方便在编译期初始化的对象进行赋值,或者说对一些静态常量进行初始化操作。
总结
- loadheinitlize方法都会在实例化对象之前调用
- load执行在main函数之前,initlize执行在main函数之后
- 这两个方法会被自动调用,最好不要手动调用;
- load和initlize有关父类的调用都是隐式 ;
- 子类没有initialize方法也会调用父类的方法,而load方法则不会调用父类
- initialize方法对一个类而言只会调用一次(Person、或者是Person+Category)都是一个Perosn类。load方法则是每个都会调用,只要你写了load方法,添加到工程都会实现。
- load方法通常用来进行Method Swizzle,initialize方法一般用于初始化全局变量或静态变量。
- load和initialize方法内部使用了锁,因此它们是线程安全的。实现时要尽可能保持简单,避免阻塞线程,不要再使用锁。