+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里面發現
-
initialize_01.jpeg
局部分析:
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);
}
。。。
}
友情鏈接: