+initialize方法
面试题:
1.+initilize方法什么时候调用?
析:+initialize方法会在【类】第一次接收到消息的时候调用
2.+initilize方法调用顺序?
析:a.先调用父类的+initilize方法,再调用子类的+initilize方法
(先初始化父类,再初始化子类,每个类只会初始化一次)
3.+initilize和+load方法的区别?
析:+initilize方法是通过消息转发机制(objc_msgSend)去实现的
而+load方法,系统调用的时候是根据方法的地址去调用的
4.+initilize方法的特点?
析:如果子类没有实现+initilize方法,会调用父类的+initilize(所以父类的initilize可能会被调用多次)
如果分类实现了+initilize方法,则会覆盖类本身的+initilize方法
5.+initilize底层原理?
析:见下分析
准备:首先搭建好可以跑runtime源码的过程,参考配置运行objc4-750和使用
gitHub_Demo
下面我们逐个分析
1.+initialize方法会在【类】第一次接收到消息的时候调用
Animal.h
#import <Foundation/Foundation.h>
@interface Animal : NSObject
@end
Animal.m
#import "Animal.h"
@implementation Animal
+(void)initialize{
NSLog(@"Animal--initialize");
}
@end
main.m
#import <Foundation/Foundation.h>
#import "Animal.h"
int main(int argc, const char * argv[]) {
@autoreleasepool {
[Animal alloc]; //+initialize方法会在【类】第一次接收到消息的时候调用
}
return 0;
}
打印:Animal--initialize
-----------
2.+initilize方法调用顺序
Animal.h
#import <Foundation/Foundation.h>
@interface Animal : NSObject
@end
Animal.m
#import "Animal.h"
@implementation Animal
+(void)initialize{
NSLog(@"Animal--initialize");
}
@end
Person.h
#import "Animal.h"
@interface Person : Animal
@end
Person.m
#import "Person.h"
@implementation Person
+(void)initialize{
NSLog(@"Person--initialize");
}
@end
main.m
#import <Foundation/Foundation.h>
#import "Person.h"
int main(int argc, const char * argv[]) {
@autoreleasepool {
[Person alloc];
//先调用父类的+initilize方法,再调用子类的+initilize方法
//先初始化父类,再初始化子类,每个类只会初始化一次
}
return 0;
}
打印:Animal--initialize
Person--initialize
---------------
3.如果子类没有实现+initilize方法,会调用父类的+initilize(父类的initilize可能会被调用多次)
会被调用多次原因:子类米有实现initialize的方法(通过superclass_isa调用的),但这并不代表父类初始化了多次
Animal.h
#import <Foundation/Foundation.h>
@interface Animal : NSObject
@end
Animal.m
#import "Animal.h"
@implementation Animal
+(void)initialize{
NSLog(@"Animal--initialize");
}
@end
Person.h
#import "Animal.h"
@interface Person : Animal
@end
Person.m
#import "Person.h"
@implementation Person
@end
main.m
#import <Foundation/Foundation.h>
#import "Person.h"
int main(int argc, const char * argv[]) {
@autoreleasepool {
[Person alloc];
}
return 0;
}
打印:Animal--initialize
Animal--initialize
-----------------
4.分类实现了+initilize方法,则会覆盖类本身的+initilize方法
Animal.h
#import <Foundation/Foundation.h>
@interface Animal : NSObject
@end
Animal.m
#import "Animal.h"
@implementation Animal
+(void)initialize{
NSLog(@"Animal--initialize");
}
@end
Person.h
#import "Animal.h"
@interface Person : Animal
@end
Person.m
#import "Person.h"
@implementation Person
+(void)initialize{
NSLog(@"Person--initialize");
}
@end
Person+myPerson.h
#import "Person.h"
@interface Person (myPerson)
@end
Person+myPerson.m
#import "Person+myPerson.h"
@implementation Person (myPerson)
+(void)initialize{
NSLog(@"Person(myPerson)--initialize");
}
@end
main.m
#import <Foundation/Foundation.h>
#import "Person.h"
int main(int argc, const char * argv[]) {
@autoreleasepool {
[Person alloc];
}
return 0;
}
打印:Animal--initialize
Person(myPerson)--initialize
源码分析
-
由于objc_msgSend的底层是通过汇编实现的 (这里第一步可详看objc-msg-arm64.s 里面的objc_msgSend)
-
我们在editScheme->run->Arguments->OBJC_PRINT_INITIALIZE_METHODS:YES
-
我们发现:在后台打印了
objc[93254]: INITIALIZE: thread 0x1000be5c0: calling +[Animal initialize] 2019-03-10 22:45:45.984948+0800 04.initilize方法[93254:6315621] Animal--initialize objc[93254]: INITIALIZE: thread 0x1000be5c0: finished +[Animal initialize] objc[93254]: INITIALIZE: thread 0x1000be5c0: Animal is fully +initialized objc[93254]: INITIALIZE: thread 0x1000be5c0: calling +[Person initialize] 2019-03-10 22:45:45.985338+0800 04.initilize方法[93254:6315621] Person(myPerson)--initialize objc[93254]: INITIALIZE: thread 0x1000be5c0: finished +[Person initialize] objc[93254]: INITIALIZE: thread 0x1000be5c0: Person is fully +initialized Program ended with exit code: 0
-
由此,我们发现几个关键字:【calling +】、【finished +】、【is fully +initialized】
-
我们在objc-runtime-new.mm里面发现
-
局部分析:
void _class_initialize(Class cls)
{
assert(!cls->isMetaClass());
Class supercls;
bool reallyInitialize = NO;
//先调用父类的+initilize方法,再调用子类的+initilize方法
//(先初始化父类,再初始化子类,每个类只会初始化一次)
//如果子类没有实现+initilize方法,会调用父类的+initilize(所以父类的initilize可能会被调用多次)
supercls = cls->superclass;
if (supercls && !supercls->isInitialized()) {
_class_initialize(supercls);
}
。。。
}
友情链接:
网友评论