load和initial个人理解
在上次面试字节的时候还记得面试官曾问过这个问题,当时虽然大体上答对了,但回想起来还是有些地方有些模糊,所以这次再对这个问题进行一下深入的分析。
load方法
+(void)load
load方法会在程序第一次加载到内存中时,即在main函数调用前就会调用,且仅会调用一次,与这个类或分类是否被用到无关。例如只要在系统文件中包含了某个类的文件,就算mian函数中没有引用该类的.h文件,那么当运行main函数之前,在objc运行时也会调用该类文件的load方法。
load方法调用的顺序基于:根类—>...—>父类—>子类—>分类。如果当中哪个类没有实现load方法也不会调用其父类load方法,该方法并不遵从继承规则。代码例如:
//父类
@interface BaseClass : NSObject
@end
@implementation BaseClass
+(void)load{
NSLog(@"%@",self);
}
@end
//子类
@interface SubClass : BaseClass
@end
@implementation SubClass
+(void)load{
NSLog(@"%@",self);
}
@end
//分类
@interface BaseClass (CategoryClass)
@end
@implementation BaseClass (CategoryClass)
+(void)load{
NSLog(@"%@(CategoryClass)",self);
}
@end
在main函数中执行,结果如下:
2020-05-19 15:22:27.360920+0800 effective-OC-test[97297:2862157] BaseClass
2020-05-19 15:22:27.361262+0800 effective-OC-test[97297:2862157] SubClass
2020-05-19 15:22:27.361323+0800 effective-OC-test[97297:2862157] BaseClass(CategoryClass)
在load函数中调用self,返回的是类的类型:Class,与类方法中的+(Class)class和类对象方法的-(Class)class的返回结果一样。
注意事项:因为在系统载入不同类的时候,载入顺序是不可预知的,所以在load方法中不能使用其他类,其他类在该类调用load方法前可能并未加载,所以使用其他类是不安全的。
initial方法
+(void)initialize
initial方法与load相似之处在于,在系统的加载过程中,只会加载一次,都不需要在类方法中去调用[super load]或[super initial]。
不同点在于:
-
initial方法采用的是懒加载策略。只有当系统发消息给该类对象时就会加载该方法,例如在申请内存空间的类方法:+ (instancetype)alloc中就会调用该类的initial方法。 -
initial方法的调用顺序为:(分类)—>根类—>父类—>...—>字类,其中如果分类重写了initial方法,则会覆盖掉原来类的initial方法。如果字类没有覆写父类的initial方法,则会根据继承规则,当调用到字类时,会把父类的initial方法继承过来调用一遍。代码如下://父类 @interface BaseClass : NSObject @end @implementation BaseClass +(void)initialize{ NSLog(@"initialize:%@",self); } @end //子类 @interface SubClass : BaseClass @end @implementation SubClass +(void)initialize{ NSLog(@"initialize:%@",self); } @end //父类的分类 @interface BaseClass (CategoryClass) @end @implementation BaseClass (CategoryClass) +(void)initialize{ NSLog(@"initialize:%@(catagoryClass)",self); } @end int main(int argc, const char * argv[]) { SubClass* sub=[SubClass new]; return 0; }结果如下:
2020-05-19 17:41:35.434074+0800 effective-OC-test[9418:3000392] initialize:BaseClass(catagoryClass) 2020-05-19 17:41:36.151008+0800 effective-OC-test[9418:3000392] initialize:SubClass Program ended with exit code: 0由此可见,分类的
initial方法已经将父类的方法覆写。如果这时候把子类:SubClass的
initial方法注释掉,这时候再执行,结果如下:2020-05-19 17:44:53.126457+0800 effective-OC-test[9686:3003267] initialize:BaseClass(catagoryClass) 2020-05-19 17:44:54.613843+0800 effective-OC-test[9686:3003267] initialize:SubClass(catagoryClass) Program ended with exit code: 0这时候会打印两遍分类的
initial方法,只不过self的参数已经变为了SubClass。出现这种情况的原因就是因为SubClass没有覆写其父类(这时候已变为了父类的分类),当执行到字类时,系统会把父类(分类)的initial方法继承来调用,但这时候调用的self已经变为了当前的子类:SubClass,所以会打印出:initialize:SubClass(catagoryClass)。
总结
- 虽然可以控制不同类的
initial方法调用顺序,但是同load方法一样,不建议在其内部调用其他自定义类,有时可能还会出现死锁现象。 load方法在执行的时候会阻塞整个应用,所以应减少其内部的执行操作,尽量不要在该方法内执行耗时任务。initial方法内部通常用来对类内部的静态变量执行初始化操作。