首先代码展示吧,后面也会附赠demo代码链接
1.定义测试类TestClass
//为了方便打印,先在宏定义文件里面定义ZWWLog
#ifdef DEBUG
#define ZWWLog(fmt, ...) NSLog((@"%s [Line %d] " fmt), __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__);
#else
#define ZWWLog(...)
#endif
TestClass.m
+ (void)load{
ZWWLog();
}
+ (void)initialize
{
ZWWLog(@"TestClass 中的initialize方法执行 class:%@",[self class]);
}
- (instancetype)init{
ZWWLog(@"TestClass 中的init方法执行 class:%@",[self class]);
return [super init];
}
2.定义测试类TestClass的子类TestClassSon
TestClassSon.m
+ (void)load{
ZWWLog();
}
+ (void)initialize
{
ZWWLog();
}
- (instancetype)init
{
ZWWLog();
return [super init];
}
2.定义测试类TestClass的分类1TestClass (Method)
//不会覆盖主类的load
+ (void)load{
ZWWLog();
}
//会覆盖主类的initialize
//+ (void)initialize
//{
// if (self == [self class]) {
// ZWWLog();
// }
//}
//会覆盖主类的init方法
//- (instancetype)init
//{
// ZWWLog(@"TestClass (Method) init方法执行");
// self = [super init];
// if (self) {
//
// }
// return self;
//}
2.定义测试类TestClass的分类2TestClass (Method1)
+ (void)load{
ZWWLog();
}
//+ (void)initialize
//{
// if (self == [self class]) {
// ZWWLog();
// }
//}
//- (instancetype)init
//{
// ZWWLog(@"TestClass (Method1) init方法执行");
// self = [super init];
// if (self) {
//
// }
// return self;
//}
好了,代码准备完毕,下面在控制器中调用类,根据打印结果总结结论:
在控制器中需要导入对应头文件
#import "TestClass.h"
#import "TestClassSon.h"
#import "TestClass+Method.h"
#import "TestClass+method1.h"
1.load方法测试:什么操作也不做,直接commond+b编译,打印如下:
2018-10-04 14:47:17.766168+0800 InterviewDemo[4064:619260] +[TestClass load] [Line 26]
2018-10-04 14:47:17.766824+0800 InterviewDemo[4064:619260] +[TestClassSon load] [Line 14]
2018-10-04 14:47:17.778301+0800 InterviewDemo[4064:619260] +[TestClass(Method) load] [Line 28]
2018-10-04 14:47:17.778399+0800 InterviewDemo[4064:619260] +[TestClass(method1) load] [Line 13]
如果你导入别的头文件,重写load方法进行打印的话,同样也可以看到该类load方法被执行
在Bulid Phases->Compile Sources调整分类的编译顺序
打印结果:
2018-10-04 14:49:02.275479+0800 InterviewDemo[4101:628305] +[TestClass load] [Line 26]
2018-10-04 14:49:02.276066+0800 InterviewDemo[4101:628305] +[TestClassSon load] [Line 14]
2018-10-04 14:49:02.306659+0800 InterviewDemo[4101:628305] +[TestClass(method1) load] [Line 13]
2018-10-04 14:49:02.306799+0800 InterviewDemo[4101:628305] +[TestClass(Method) load] [Line 28]
可以看到两个分类的load方法调用顺序改变了
结论:
load方法相关要点:
load方法设深层理解及加载时机参考链接:
load方法深层理解
2.initialize和init方法测试:在控制器中输入以下代码(分类的initialize和init方法先注释掉):
TestClass *testCls1 = [[TestClass alloc]init];
TestClass *testCls2 = [[TestClass alloc]init];
TestClass *testCls3 = [[TestClass alloc]init];
打印结果:
2018-10-04 14:56:28.354678+0800 InterviewDemo[4231:658017] +[TestClass initialize] [Line 31] TestClass 中的initialize方法执行 class:TestClass
2018-10-04 14:56:28.354878+0800 InterviewDemo[4231:658017] -[TestClass init] [Line 36] TestClass 中的init方法执行 class:TestClass
2018-10-04 14:56:28.354968+0800 InterviewDemo[4231:658017] -[TestClass init] [Line 36] TestClass 中的init方法执行 class:TestClass
2018-10-04 14:56:28.355034+0800 InterviewDemo[4231:658017] -[TestClass init] [Line 36] TestClass 中的init方法执行 class:TestClass
结果:TestClass实例化3次,initialize执行1次,init方法执行3次
替换输入以下代码
// TestClass *testCls1 = [[TestClass alloc]init];
// TestClass *testCls2 = [[TestClass alloc]init];
// TestClass *testCls3 = [[TestClass alloc]init];
TestClassSon *testClsSon1 = [[TestClassSon alloc]init];
TestClassSon *testClsSon2 = [[TestClassSon alloc]init];
TestClassSon *testClsSon3 = [[TestClassSon alloc]init];
情况1:父类,子类都实现了initialize,init方法,父类分类未实现initialize,init方法,打印结果
2018-10-04 14:59:38.183968+0800 InterviewDemo[4301:670394] +[TestClass initialize] [Line 31] TestClass 中的initialize方法执行 class:TestClass
2018-10-04 14:59:38.184082+0800 InterviewDemo[4301:670394] +[TestClassSon initialize] [Line 19]
2018-10-04 14:59:38.184158+0800 InterviewDemo[4301:670394] -[TestClassSon init] [Line 25]
2018-10-04 14:59:38.184244+0800 InterviewDemo[4301:670394] -[TestClass init] [Line 36] TestClass 中的init方法执行 class:TestClassSon
2018-10-04 14:59:38.184311+0800 InterviewDemo[4301:670394] -[TestClassSon init] [Line 25]
2018-10-04 14:59:38.184375+0800 InterviewDemo[4301:670394] -[TestClass init] [Line 36] TestClass 中的init方法执行 class:TestClassSon
2018-10-04 14:59:38.184432+0800 InterviewDemo[4301:670394] -[TestClassSon init] [Line 25]
2018-10-04 14:59:38.184494+0800 InterviewDemo[4301:670394] -[TestClass init] [Line 36] TestClass 中的init方法执行 class:TestClassSon
结果:
父类initialize,子类initialize都只执行1次,子类init,父类init各执行3次;
因为代码子类init方法中,后调用的 [super init](看下面代码),所以父类init在后面执行。将 [super init] 放到ZWWLog()前面,就会先调用父类init方法,下面是子类中的init方法实现
- (instancetype)init
{
ZWWLog();
return [super init];
}
情况2:父类实现initialize,init,子类未实现initialize(注释掉子类的方法),实现init,父类的分类未实现initialize,init情况,打印结果:
2018-10-04 15:02:50.767970+0800 InterviewDemo[4360:682382] +[TestClass initialize] [Line 31] TestClass 中的initialize方法执行 class:TestClass
2018-10-04 15:02:50.768151+0800 InterviewDemo[4360:682382] +[TestClass initialize] [Line 31] TestClass 中的initialize方法执行 class:TestClassSon
2018-10-04 15:02:50.768222+0800 InterviewDemo[4360:682382] -[TestClassSon init] [Line 25]
2018-10-04 15:02:50.768294+0800 InterviewDemo[4360:682382] -[TestClass init] [Line 36] TestClass 中的init方法执行 class:TestClassSon
2018-10-04 15:02:50.768348+0800 InterviewDemo[4360:682382] -[TestClassSon init] [Line 25]
2018-10-04 15:02:50.768401+0800 InterviewDemo[4360:682382] -[TestClass init] [Line 36] TestClass 中的init方法执行 class:TestClassSon
2018-10-04 15:02:50.768449+0800 InterviewDemo[4360:682382] -[TestClassSon init] [Line 25]
2018-10-04 15:02:50.768531+0800 InterviewDemo[4360:682382] -[TestClass init] [Line 36] TestClass 中的init方法执行 class:TestClassSon!
结果:父类执行2次initialize。1次父类本身的initialize,1次代替子类的initialize。父类和子类init方法各调用3次
情况3:父类,子类,父类的分类都实现initialize;父类、子类实现init,分类未实现init方法情况,打印结果:
2018-10-04 15:04:39.997736+0800 InterviewDemo[4406:691826] +[TestClass(Method) initialize] [Line 35]
2018-10-04 15:04:39.997908+0800 InterviewDemo[4406:691826] +[TestClassSon initialize] [Line 19]
2018-10-04 15:04:39.997983+0800 InterviewDemo[4406:691826] -[TestClassSon init] [Line 25]
2018-10-04 15:04:39.998105+0800 InterviewDemo[4406:691826] -[TestClass init] [Line 36] TestClass 中的init方法执行 class:TestClassSon
2018-10-04 15:04:39.998164+0800 InterviewDemo[4406:691826] -[TestClassSon init] [Line 25]
2018-10-04 15:04:39.998229+0800 InterviewDemo[4406:691826] -[TestClass init] [Line 36] TestClass 中的init方法执行 class:TestClassSon
2018-10-04 15:04:39.998286+0800 InterviewDemo[4406:691826] -[TestClassSon init] [Line 25]
2018-10-04 15:04:39.998348+0800 InterviewDemo[4406:691826] -[TestClass init] [Line 36] TestClass 中的init方法执行 class:TestClassSon
结果:父类的分类initialize执行1次(父类被分类覆盖掉),子类initialize执行1次,父类init,子类init各执行3次
情况4:父类,子类,父类的分类都实现initialize,init方法情况,打印结果:
2018-10-04 15:09:16.464298+0800 InterviewDemo[4483:707765] +[TestClass(Method) initialize] [Line 35]
2018-10-04 15:09:16.464429+0800 InterviewDemo[4483:707765] +[TestClassSon initialize] [Line 19]
2018-10-04 15:09:16.464502+0800 InterviewDemo[4483:707765] -[TestClassSon init] [Line 25]
2018-10-04 15:09:16.464615+0800 InterviewDemo[4483:707765] -[TestClass(Method) init] [Line 42] TestClass (Method) init方法执行
2018-10-04 15:09:16.464674+0800 InterviewDemo[4483:707765] -[TestClassSon init] [Line 25]
2018-10-04 15:09:16.464739+0800 InterviewDemo[4483:707765] -[TestClass(Method) init] [Line 42] TestClass (Method) init方法执行
2018-10-04 15:09:16.464784+0800 InterviewDemo[4483:707765] -[TestClassSon init] [Line 25]
2018-10-04 15:09:16.464854+0800 InterviewDemo[4483:707765] -[TestClass(Method) init] [Line 42] TestClass (Method) init方法执行
分类的编译顺序:
结果:分类initialize代替父类initialize执行一次,分类init代替父类init方法执行3次,子类init方法执行3次
综合上面四种情况得出结论:
initialize方法相关要点
总结:
load和initialize有很多共同特点,下面简单列一下:
init和initialize区别:
initialize不是init,initialize在程序运行过程中,它会在你程序中每个类调用仅一次initialize。这个调用的时间发生在你的类接收到消息之前,但是在它的父类接收到initialize之后。
init则是你手动初始化几次就调用几次,和普通方法一样
下面是demo代码形式验证常见面试原理问题链接,有问题欢迎指正,探讨~~
demo代码