1. +load 和+initialize调用时机次数
声明类Person
和Person+Category
// // Person.m // LoadInitializeDemo // // Created by Ternence on 2021/5/10. // #import "Person.h" @implementation Person + (void)load { [super load]; NSLog(@"\n Person +load \n "); } + (void)initialize { [super initialize]; NSLog(@"\n Person +initialize"); } @end
// // Person+Category.m // LoadInitializeDemo // // Created by Ternence on 2021/5/10. // #import "Person+Category.h" @implementation Person (Category) + (void)load { [super load]; NSLog(@"\n Person Category +load \n "); } + (void)initialize { [super initialize]; NSLog(@"\n Person Category +initialize \n "); } @end
不调用不引用不用该类创建实例对象,启动App。查看打印
2021-05-10 14:47:05.534059+0800 LoadInitializeDemo[37437:645704] Person +load Person Category +load
在其它类创建一个Person实例:
- (void)viewDidLoad { [super viewDidLoad]; Person *person1 = [[Person alloc] init]; NSLog(@"person1 created"); Person *person2 = [[Person alloc] init]; NSLog(@"person2 created"); }
查看打印:
Person +load Person Category +load Person Category +initialize person1 created person2 created
对比两次打印结果,我们可以得出结论:
- 创建该类后不创建实例,发现+load调用了,且在main函数之前调用,+initialize并未调用
- 首次创建该类的实例的时候+initialize调用了,之后再没有调用
- 类和分类的+load都会在main函数之前调用
- +load 和+initialize 都只调用一次
2. 父类子类调用 +load 和 +initialize的先后顺序
创建Student
和Student+Category
继承自Person
,不引用不调用Person
、Student
,查看代码打印
2021-05-10 15:23:45.758752+0800 LoadInitializeDemo[59531:714585] Person +load Person Category +initialize Person Category +load Student +load Person Category +load Person Category +load Student Category +load
结论:
+load
- 先调用类的+load,后调用分类的+load
- 先调用父类+load,后调用子类的+load
- 按照编译顺序调用+load(先编译先调用)
+initialize
- 先初始化分类,后初始化子类
- 先调用父类,后调用子类
3. 总结
- load是runtime加载类、分类的时候调用(只会调用一次)
- initialize是类第一次接收到消息的时候调用, 每一个类只会initialize一次(如果子类没有实现initialize方法, 会调用父类的initialize方法, 所以父类的initialize方法可能会调用多次)
4. +load使用场景
Runtime Swizzing 方法时,应该在+load方法中调用,因为此方法在类编译后,main函数之前,切只调用依次
5. +load源码阅读
官方源码地址:objc4
调用顺序:查看objc-os.mm
_objc_init
load_images
prepare_load_methods
schedule_class_load
add_class_to_loadable_list
add_category_to_loadable_list
call_load_methods
call_class_loads
call_category_loads
load_method_t
6. +initialize源码阅读
调用顺序:
objc-msg-arm64.s
_objc_msgSend
objc-runtime-new.mm
class_getInstanceMethod
lookUpImpOrForward
__class_initialize
callInitialize
objc_msgSend