(三)+initialize方法

+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);
    }
    。。。    
}

友情鏈接:

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。