load和initialize的执行过程经常被问到在这里简单梳理一番
load方法
分别创建类Person和Car并实现load方法
#import "Person.h"
@implementation Person
+(void)load{
NSLog(@"%s %@",__FUNCTION__,[self class]);
}
@end
#import "Car.h"
@implementation Car
+(void)load{
NSLog(@"%s %@",__FUNCTION__,[self class]);
}
@end
执行结果
验证了load方法执行顺序就是编译顺序
这时候没有用到这两个类,在Compile Sources中删除之,看看运行结果
可以运行成功但是load方法都没有执行,这是因为我们现在没有用到这个Class
即使在ViewController中引入Person.h头文件也没有问题,这是因为OC是一门动态语言在编译时不检查方法是否实现
用到Person类时就会报错了
//运行报错,Compile Sources中添加类Person和Car问题解决
[Person class];
这个时候了解了load方法是在编译时执行的,load执行顺序就是Compile Sources列表中的顺序,一个类只会被编译一次,所以一个类的load方法也只会执行一次
子类load方法
创建子类Student
#import "Person.h"
NS_ASSUME_NONNULL_BEGIN
@interface Student : Person
@end
NS_ASSUME_NONNULL_END
#import "Student.h"
@implementation Student
+(void)load{
NSLog(@"%s %@",__FUNCTION__,[self class]);
}
@end
运行结果
这时先执行父类load再执行子类load,跟Compile Sources中顺序就没有关系了,手动删除子类Student或者父类Person也都没有问题,可以正常运行。
Category中的load方法
创建Person类的Category,Person+Study
#import "Person.h"
NS_ASSUME_NONNULL_BEGIN
@interface Person (Study)
@end
NS_ASSUME_NONNULL_END
#import "Person+Study.h"
@implementation Person (Study)
+ (void)load{
NSLog(@"%s %@",__FUNCTION__,[self class]);
}
@end
执行结果
这个时候执行结果先执行父类load再执行子类load,最后执行分类Category中的load方法,顺序跟Compile Sources中顺序无关,在用不到分类是从Compile Sources列表中删除也可以正常运行,但是如果有多个分类的话就按照Compile Sources中的顺序执行分类中的load方法了
initialize方法
如果父类Person和子类Student以及分类Person+Study都实现了initialize方法
#import "Person.h"
@implementation Person
+ (void)initialize
{
NSLog(@"Person类%s %@",__FUNCTION__,[self class]);
}
@end
#import "Student.h"
@implementation Student
+ (void)initialize
{
NSLog(@"Student类%s %@",__FUNCTION__,[self class]);
}
@end
#import "Person+Study.h"
@implementation Person (Study)
+ (void)initialize{
NSLog(@"分类 %s %@",__FUNCTION__,[self class]);
}
@end
当给Class发送第一条消息时
#import "ViewController.h"
#import "Person.h"
#import "Student.h"
#import "Person+Study.h"
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
[Student alloc];
// Do any additional setup after loading the view.
}
@end
可以看到执行结果
分类 +[Person(Study) initialize] Person
Student类+[Student initialize] Student
先执行了分类中的initialize再执行子类的initialize,难道分类会覆盖Person类中的initialize??先删除分类看看结果
Person类+[Person initialize] Person
Student类+[Student initialize] Student
果然分类会覆盖Person类中的initialize,再将Person类中的initialize注释掉执行以下
Student类+[Student initialize] Student
只执行了子类的initialize方法,如果父类实现了initialize方法但是子类没有实现了
Person类+[Person initialize] Person
Person类+[Person initialize] Student
发现调用了两次父类中的initialize方法,通过类型判断可以区分父类还是子类以及是哪一个字类
小结:
- 分类中的initialize会覆盖initialize
- 先调用字类中的initialize再调用父类的initialize
- 子类实现了initialize父类没实现那么创建子类对象只调用一次
- 子类没有实现initialize但是父类实现了initialize,那么创建子类时调用两次父类的initialize,通过类型判断可加以区分