本文demo在这里LoadAndInitializeDemo
Load方法执行时机和执行顺序
load方法是在main函数前调用的,引入项目中就会调用,且只会调用一次,那么当类和类的Category都有load方法是怎么调用的?类有多个Category,且都实现了load方法又是怎么调用的?子类和父类都实现了load方法是怎么调用的?带着这些问题,我们来看下下面的结论和测试用例。
测试用例:
**类关系:**
==========================
人类:XMPeople
XMPeople:NSObject
XMPeople (Category1)
XMPeople (Category2)
人类子类:XMMan
XMMan:XMPeople
XMMan (Category1)
XMMan (Category2)
人类子类:XMWoman
XMWoman:XMPeople
==========================
动物类:XMWoman
XMAnimal : NSObject
==========================
#pragma ==========================
#pragma 人类:XMPeople
#pragma ==========================
@implementation XMPeople
+ (void)load
{
NSLog(@"%@==========%@", NSStringFromSelector(_cmd), [self class]);
}
@end
@implementation XMPeople (Category1)
+ (void)load
{
NSLog(@"%@==========%@Category1", NSStringFromSelector(_cmd), [self class]);
}
@end
@implementation XMPeople (Category2)
+ (void)load
{
NSLog(@"%@==========%@Category2", NSStringFromSelector(_cmd), [self class]);
}
@end
#pragma ==========================
#pragma 人类子类:XMMan
#pragma ==========================
@implementation XMMan
+ (void)load
{
NSLog(@"%@==========%@", NSStringFromSelector(_cmd), [self class]);
}
@end
@implementation XMMan (Category1)
+ (void)load
{
NSLog(@"%@==========%@Category1", NSStringFromSelector(_cmd), [self class]);
}
@end
@implementation XMMan (Category2)
+ (void)load
{
NSLog(@"%@==========%@Category2", NSStringFromSelector(_cmd), [self class]);
}
@end
#pragma ==========================
#pragma 人类子类:XMWoman
#pragma ==========================
@implementation XMWoman
@end
#pragma ==========================
#pragma 动物类:XMAnimal
#pragma ==========================
@implementation XMAnimal
+ (void)load
{
NSLog(@"%@==========%@", NSStringFromSelector(_cmd), [self class]);
}
@end
类文件编译顺序:

输出结果:
2019-05-14 17:09:53.867210+0800 LoadAndInitalizeDemo[9511:2236726] load==========XMAnimal
2019-05-14 17:09:53.867725+0800 LoadAndInitalizeDemo[9511:2236726] load==========XMPeople
2019-05-14 17:09:53.867813+0800 LoadAndInitalizeDemo[9511:2236726] load==========XMMan
2019-05-14 17:09:53.867913+0800 LoadAndInitalizeDemo[9511:2236726] load==========XMManCategory2
2019-05-14 17:09:53.867979+0800 LoadAndInitalizeDemo[9511:2236726] load==========XMPeopleCategory1
2019-05-14 17:09:53.868071+0800 LoadAndInitalizeDemo[9511:2236726] load==========XMManCategory1
2019-05-14 17:09:53.868179+0800 LoadAndInitalizeDemo[9511:2236726] load==========XMPeopleCategory2
结论:
1.当类和类Category中load方法都存在时,先调用类中load方法,Category中load方法后调用(注意:Category中load晚于所有的类中load方法调用)
2.父类load方法优先于子类load方法(参考人类子类:XMMan和人类:XMPeople)
3.子类没实现load方法,不会调用父类load方法(参考人类子类:XMWoman)
4.Category的load调用顺序,与对应类之间的关系无关,与编译顺序一致(参考XMPeople (Category1)、XMPeople (Category2)、 XMMan (Category1)、XMMan (Category2) )
5.类与类的Category中的load方法都会调用
6.当有多个类时,load调用顺序和类文件编译顺序有关(参考动物类:XMAnimal和人类:XMPeople)
Initialize方法执行顺序
Initialize方法是在类第一次初始化的时候调用的,且只调用一次,但是在子类和父类都是有Initialize方法的时候,是怎么调用的呢?类和Category中都有Initialize又是怎么调用的? 子类没有实现Initialize方法,会不会调用父类的Initialize方法呢?带着这些问题,我们可以看下下面的结论和测试实验。
测试用例:
#pragma ==========================
#pragma 人类:XMPeople
#pragma ==========================
@implementation XMPeople
+ (void)initialize
{
NSLog(@"%@==========%@", NSStringFromSelector(_cmd), [self class]);
}
@end
@implementation XMPeople (Category1)
+ (void)initialize
{
NSLog(@"%@==========%@Category1", NSStringFromSelector(_cmd), [self class]);
}
@end
@implementation XMPeople (Category2)
+ (void)initialize
{
NSLog(@"%@==========%@Category2", NSStringFromSelector(_cmd), [self class]);
}
@end
#pragma ==========================
#pragma 人类子类:XMMan
#pragma ==========================
@implementation XMMan
+ (void)initialize
{
NSLog(@"%@==========%@", NSStringFromSelector(_cmd), [self class]);
}
@end
@implementation XMMan (Category1)
+ (void)initialize
{
NSLog(@"%@==========%@Category1", NSStringFromSelector(_cmd), [self class]);
}
@end
@implementation XMMan (Category2)
+ (void)initialize
{
NSLog(@"%@==========%@Category2", NSStringFromSelector(_cmd), [self class]);
}
@end
#pragma ==========================
#pragma 人类子类:XMWoman
#pragma ==========================
@implementation XMWoman
@end
类文件编译顺序:

实例对象创建顺序和输出记过:
测试1:
XMPeople *people = [XMPeople new];
结果1:
2019-05-14 18:11:46.710885+0800 LoadAndInitalizeDemo[25371:2328024] initialize==========XMPeopleCategory2
**************************************************************************************
测试2:
XMMan *man = [XMMan new];
结果2:
2019-05-14 17:41:23.177725+0800 LoadAndInitalizeDemo[18632:2284715] initialize==========XMPeopleCategory2
2019-05-14 17:41:23.177871+0800 LoadAndInitalizeDemo[18632:2284715] initialize==========XMManCategory1
**************************************************************************************
测试3:
XMMan *man = [XMMan new];
XMPeople *people = [XMPeople new];
结果3:
2019-05-14 18:10:16.282968+0800 LoadAndInitalizeDemo[25059:2325808] initialize==========XMPeopleCategory2
2019-05-14 18:10:16.283091+0800 LoadAndInitalizeDemo[25059:2325808] initialize==========XMManCategory1
**************************************************************************************
测试4:
XMWoman *woman = [XMWoman new];
结果4:
2019-05-14 17:56:06.076544+0800 LoadAndInitalizeDemo[22157:2306915] initialize==========XMPeopleCategory2
2019-05-14 17:56:06.076775+0800 LoadAndInitalizeDemo[22157:2306915] initialize==========XMWomanCategory2
结论:
1.如果类和类Category都实现了initialize方法,调用Category的initialize方法,会覆盖类中的方法,只执行一个,如果多个category,则调用编译顺序最后的initialize方法。(测试1)
2.如果父类和子类都实现了initialize方法,在调用子类时,如果父类的initialize方法调用过,则只调用子类initialize方法,如果父类没用过,则先调用父类的Category的initialize方法,在调用子类的initialize方法(测试2)。如果调用子类的时候,已经初始化过父类的initialize,则在初始化父类的时候,不会再调用initialize方法(测试3)
3.如果子类没有实现initialize方法,父类实现了initialize方法,调用子类的时候,会先调用父类的initialize方法,再调用子类的实例方法。(测试4)
总结:
Load执行顺序总结
1.当类和类Category中load方法都存在时,先调用类中load方法,Category中load方法后调用(注意:Category中load晚于所有的类中load方法调用)
2.父类load方法优先于子类load方法(参考人类子类:XMMan和人类:XMPeople)
3.子类没实现load方法,不会调用父类load方法(参考人类子类:XMWoman)
4.Category的load调用顺序,与对应类之间的关系无关,与编译顺序一致(参考XMPeople (Category1)、XMPeople (Category2)、 XMMan (Category1)、XMMan (Category2) )
5.类与类的Category中的load方法都会调用
6.当有多个类时,load调用顺序和类文件编译顺序有关(参考动物类:XMAnimal和人类:XMPeople)
initialize执行顺序总结
1.如果类和类Category都实现了initialize方法,调用Category的initialize方法,会覆盖类中的方法,只执行一个,如果多个category,则调用编译顺序最后的initialize方法。(测试1)
2.如果父类和子类都实现了initialize方法,在调用子类时,如果父类的initialize方法调用过,则只调用子类initialize方法,如果父类没用过,则先调用父类的Category的initialize方法,在调用子类的initialize方法(测试2)。如果调用子类的时候,已经初始化过父类的initialize,则在初始化父类的时候,不会再调用initialize方法(测试3)
3.如果子类没有实现initialize方法,父类实现了initialize方法,调用子类的时候,会先调用父类的initialize方法,再调用子类的实例方法。(测试4)
参考:
Objective-C 深入理解 +load 和 +initialize
iOS类方法load和initialize详解
网友评论