iOS-load和initialize方法

在iOS中,所有的類都繼承自NSObject,我們來(lái)看一下初始化相關(guān)的幾個(gè)方法

+ (void)load;
+ (void)initialize;
- (instancetype)init ;

+ (instancetype)new OBJC_SWIFT_UNAVAILABLE("use object initializers instead");
+ (instancetype)allocWithZone:(struct _NSZone *)zone OBJC_SWIFT_UNAVAILABLE("use object initializers instead");
+ (instancetype)alloc OBJC_SWIFT_UNAVAILABLE("use object initializers instead");
- (void)dealloc OBJC_SWIFT_UNAVAILABLE("use 'deinit' to define a de-initializer");

OBJC_SWIFT_UNAVAILABLE 宏表示只能在OC中使用,在Swift中不能使用
+(instancetype)new 可以看作是alloc與init方法的結(jié)合
+(instancetype)allocWithZone alloc也是調(diào)用該方法,參數(shù)傳NULL
+(instancetype)alloc 為對(duì)象分配內(nèi)存空間
-(instancetype)init 初始化變量
-(void)dealloc 銷毀對(duì)象時(shí)調(diào)用的方法
上面的方法是我們開發(fā)時(shí)比較常用的,也很好理解,而load和initialize這兩個(gè)方法并不常用,而且也有點(diǎn)特殊,下面我們就來(lái)詳細(xì)說(shuō)一下這兩個(gè)方法

在介紹之前,我們首先來(lái)了解一下類的使用,我們要使用一個(gè)類,大概要經(jīng)過(guò)以下步驟

  1. 啟動(dòng)App,程序開始加載類到內(nèi)存中(代碼區(qū))+(void)load
  2. 首次使用該類時(shí),創(chuàng)建類對(duì)象(我們可以把它看作是一個(gè)單例,它在整個(gè)程序中只有一份)+(void)initialize
  3. 通過(guò)類對(duì)象創(chuàng)建實(shí)例對(duì)象+(instancetype)alloc、-(instancetype)init
  4. 通過(guò)實(shí)例對(duì)象,我們就可使用實(shí)例方法、類屬性了

從上面的步驟我們也大概了解到load和initialize的調(diào)用時(shí)機(jī)了,下面在來(lái)詳細(xì)說(shuō)一下

+(void)load

  1. 在App啟動(dòng)后立即加載類,此時(shí)就會(huì)調(diào)用該函數(shù),所以它的調(diào)用時(shí)機(jī)很早,甚至在main函數(shù)之前
  2. 兩個(gè)不相關(guān)的類的加載順序是隨機(jī)的
  3. 如果一個(gè)類沒(méi)有l(wèi)oad方法,則該類就不會(huì)調(diào)用load方法,它不會(huì)去繼承父類的load
  4. 如果兩個(gè)類有依賴關(guān)系,則優(yōu)先加載被依賴的類
  5. 如果兩個(gè)類是繼承關(guān)系,則優(yōu)先加載父類,再加載子類
  6. Category的load也會(huì)收到調(diào)用,但順序上在主類的load調(diào)用之后

所以在load方法中,我們不需要調(diào)用super,因?yàn)樵诩虞d子類之前肯定加載完成父類了,即父類的load方法肯定已經(jīng)執(zhí)行過(guò)了,同時(shí)這里也有一個(gè)缺點(diǎn),因?yàn)閘oad方法執(zhí)行時(shí),運(yùn)行環(huán)境還不確定,如果我們?cè)趌oad函數(shù)中使用了其它不相關(guān)的類,我們并不能保證該類已經(jīng)加載完成且可用,甚至有時(shí)還要自己負(fù)責(zé)做auto release處理

+(void)initialize

  1. 在首次使用類時(shí),會(huì)生成類對(duì)象,該方法在此時(shí)調(diào)用,initialize其實(shí)就是一個(gè)懶加載方法
  2. 如果兩個(gè)類是繼承關(guān)系,會(huì)先調(diào)用父類,再調(diào)用子類
  3. 如果子類沒(méi)有實(shí)現(xiàn)initialize,則會(huì)繼承父類的initialize

在initialize方法中,我們同樣不需要調(diào)用super,因?yàn)檎{(diào)用子類之前,父類已經(jīng)調(diào)用一次了,而且如果子類沒(méi)有實(shí)現(xiàn)initialize方法時(shí),在首次使用子類時(shí)還會(huì)調(diào)用一次父類的方法,它與load方法還有不同的是,在initialize調(diào)用時(shí),運(yùn)行環(huán)境基本健全(在main函數(shù)之后,我們要保證在load方法中沒(méi)有使用該類,不然initialize就沒(méi)有該優(yōu)勢(shì)),所以此時(shí)我們可以做更多的操作

上面原理講完了,下面再寫一個(gè)Demo來(lái)測(cè)試一下

一、先來(lái)測(cè)試一下load方法,下面貼出源碼,很簡(jiǎn)單
// Test繼承自NSObject
@implementation Test
+ (void)load {
    NSLog(@"load Test");
}
@end

// Test1繼承自Test類
@implementation Test1
+ (void)load {
    NSLog(@"load Test1");
}
@end

int main(int argc, char * argv[]) {
    @autoreleasepool {
        NSLog(@"main");
        return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
    }
}

下面是輸出

2018-07-24 14:17:28.113416+0800 Test[1142:222096] load Test
2018-07-24 14:17:28.113760+0800 Test[1142:222096] load Test1
2018-07-24 14:17:28.113851+0800 Test[1142:222096] main

可以看出調(diào)用順序 父類Text -> 子類Text1 -> main函數(shù)
如果注釋掉子類的load方法,則調(diào)用如下

2018-07-24 14:20:13.292581+0800 Test[1148:222715] load Test
2018-07-24 14:20:13.292943+0800 Test[1148:222715] main

這個(gè)測(cè)試沒(méi)有覆蓋load方法的所有特性,但可以測(cè)出上面所說(shuō)的load方法的第1、3、5條特性

二、再來(lái)測(cè)試一下initialize方法調(diào)用
@implementation Test
+ (void)initialize {
    NSLog(@"initialize Test");
}
@end

@implementation Test1
+ (void)initialize {
    NSLog(@"initialize Test1");
}
@end

@implementation ViewController
- (void)viewDidLoad {
    [super viewDidLoad];

    NSLog(@"首次使用Test");
    Test *obj = [[Test alloc] init];

    NSLog(@"首次使用Test1");
    Test1 *obj2 = [[Test1 alloc] init];
}
@end

輸出如下

2018-07-24 14:24:34.439448+0800 Test[1152:223417] main
2018-07-24 14:24:34.490282+0800 Test[1152:223417] 首次使用Test
2018-07-24 14:24:34.490326+0800 Test[1152:223417] initialize Test
2018-07-24 14:24:34.490346+0800 Test[1152:223417] 首次使用Test1
2018-07-24 14:24:34.490361+0800 Test[1152:223417] initialize Test1

如果注釋掉Text1的initialize方法后輸出如下

2018-07-24 14:25:25.371237+0800 Test[1154:223686] main
2018-07-24 14:25:25.423578+0800 Test[1154:223686] 首次使用Test
2018-07-24 14:25:25.423622+0800 Test[1154:223686] initialize Test
2018-07-24 14:25:25.423642+0800 Test[1154:223686] 首次使用Test1
2018-07-24 14:25:25.423655+0800 Test[1154:223686] initialize Test

從輸出可以看出上面說(shuō)的initialize的3個(gè)特性

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

相關(guān)閱讀更多精彩內(nèi)容

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