(三)+initialize方法

+initialize方法

面試題:
1.+initilize方法什么時候調(diào)用?
析:+initialize方法會在【類】第一次接收到消息的時候調(diào)用
2.+initilize方法調(diào)用順序?
析:a.先調(diào)用父類的+initilize方法,再調(diào)用子類的+initilize方法
     (先初始化父類,再初始化子類,每個類只會初始化一次)
3.+initilize和+load方法的區(qū)別?
析:+initilize方法是通過消息轉(zhuǎn)發(fā)機制(objc_msgSend)去實現(xiàn)的
   而+load方法,系統(tǒng)調(diào)用的時候是根據(jù)方法的地址去調(diào)用的

4.+initilize方法的特點?
析:如果子類沒有實現(xiàn)+initilize方法,會調(diào)用父類的+initilize(所以父類的initilize可能會被調(diào)用多次)
   如果分類實現(xiàn)了+initilize方法,則會覆蓋類本身的+initilize方法
   
5.+initilize底層原理?
析:見下分析

準(zhǔn)備:首先搭建好可以跑runtime源碼的過程,參考配置運行objc4-750和使用
gitHub_Demo

下面我們逐個分析

1.+initialize方法會在【類】第一次接收到消息的時候調(diào)用
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方法會在【類】第一次接收到消息的時候調(diào)用
    }
    return 0;
}
打?。篈nimal--initialize

-----------
2.+initilize方法調(diào)用順序
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];  
        //先調(diào)用父類的+initilize方法,再調(diào)用子類的+initilize方法
        //先初始化父類,再初始化子類,每個類只會初始化一次
    }
    return 0;
}
打印:Animal--initialize
     Person--initialize
---------------
 
3.如果子類沒有實現(xiàn)+initilize方法,會調(diào)用父類的+initilize(父類的initilize可能會被調(diào)用多次)
  會被調(diào)用多次原因:子類米有實現(xiàn)initialize的方法(通過superclass_isa調(diào)用的),但這并不代表父類初始化了多次
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;
}
打?。篈nimal--initialize
     Animal--initialize
-----------------

4.分類實現(xiàn)了+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;
}
打?。篈nimal--initialize
     Person(myPerson)--initialize

源碼分析

  • 由于objc_msgSend的底層是通過匯編實現(xiàn)的 (這里第一步可詳看objc-msg-arm64.s 里面的objc_msgSend)

  • 我們在editScheme->run->Arguments->OBJC_PRINT_INITIALIZE_METHODS:YES

    • 我們發(fā)現(xiàn):在后臺打印了

      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
      
    • 由此,我們發(fā)現(xiàn)幾個關(guān)鍵字:【calling +】、【finished +】、【is fully +initialized】

    • 我們在objc-runtime-new.mm里面發(fā)現(xiàn)

initialize_01.jpeg
局部分析:
void _class_initialize(Class cls)
{
    assert(!cls->isMetaClass());
    Class supercls;
    bool reallyInitialize = NO;

    //先調(diào)用父類的+initilize方法,再調(diào)用子類的+initilize方法
    //(先初始化父類,再初始化子類,每個類只會初始化一次)
    //如果子類沒有實現(xiàn)+initilize方法,會調(diào)用父類的+initilize(所以父類的initilize可能會被調(diào)用多次)
    supercls = cls->superclass;
    if (supercls  &&  !supercls->isInitialized()) {
        _class_initialize(supercls);
    }
    。。。    
}

友情鏈接:

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容