+load和+initialize方法都是NSObject的兩個類方法,iOS會在運(yùn)行期提前調(diào)用這兩個方法,那么我們可以在這兩個方法中做一些處理。
1、runtime并不將類的+load方法作為類的第一個方法執(zhí)行
.h文件
@interface SuperClass : NSObject
@end
@interface ChildClass : SuperClass
@end
@interface Insideinitialize : NSObject
- (void)objectMethod;
@end
.m文件
/******* Implementation *******/
@implementation SuperClass
+ (void) initialize {
NSLog(@"%@ %s", [self class], __FUNCTION__);
}
+ (void) load {
NSLog(@"%@ %s", [self class], __FUNCTION__);
}
@end
@implementation ChildClass
+ (void) initialize {
NSLog(@"%@ %s", [self class], __FUNCTION__);
Insideinitialize * obj = [[Insideinitialize alloc] init];
[obj objectMethod];
}
@end
@implementation Insideinitialize
- (void)objectMethod {
NSLog(@"%@ %s", [self class], __FUNCTION__);
}
+ (void) initialize {
NSLog(@"%@ %s", [self class], __FUNCTION__);
}
+ (void) load {
NSLog(@"%s", __FUNCTION__);
}
@end
在上面的情況下,只是引用了,打印出來

說明
就像Apple的文檔中說的一下,只要有引用runtime就會自動去調(diào)用類的+(void)load方法。不過從輸出中,我們還發(fā)現(xiàn)SuperClass的+(void)initialize也被調(diào)用了,而且是在+(void)load之前被執(zhí)行;而Insideinitialize的+(void)initialize并沒有執(zhí)行。這是因為在SuperClass的+(void)load方法中,我們調(diào)用了類的class方法([self class]),這就符合文檔中對+(void)initialize的說明:在類的第一個方法被調(diào)用前調(diào)用。同時也說明runtime對+(void)load的調(diào)用并不視為類的第一個方法。而ChildClass因為沒有用到,所以+(void)initialize的方法被沒有被執(zhí)行,而且它也沒有去執(zhí)行父類的+(void)load方法(雖然它有繼承下該方法)。
當(dāng)我們將ChildClass的+(void)load方法重寫,發(fā)現(xiàn)它有調(diào)用這個+(void)load方法
.m文件中ChildClass的實現(xiàn)
@implementation ChildClass
+ (void) initialize {
NSLog(@"%@ %s", [self class], __FUNCTION__);
Insideinitialize * obj = [[Insideinitialize alloc] init];
[obj objectMethod];
}
+ (void) load {
NSLog(@"ChildClass %s", __FUNCTION__);
}
@end
打印結(jié)果:

2、+(void)load方法可以當(dāng)做普通的類方法來調(diào)用
在程序中手動調(diào)用+load方法,同時將ChildClass的+load方法注釋掉
- (void)viewDidLoad {
[super viewDidLoad];
[ChildClass load];
}
/**
+ (void) load {
NSLog(@"ChildClass %s", __FUNCTION__);
}
*/
打印結(jié)果:

說明
前面三個結(jié)果很容易理解,不過之后ChildClass的+(void)initialize也被自動執(zhí)行調(diào)用,這個是為什么呢?因為我們是直接調(diào)用了ChildClass的類方法(+(void)load方法),所以這里會首先的調(diào)用ChildClass的+(void)initialize方法,并且我們可以在其中安全創(chuàng)建出Insideinitialize類并使用它,而Insideinitialize因為調(diào)用alloc方法是第一次使用類方法, 所以激發(fā)了Insideinitialize的+(void)initialize。
另一個方面,ChildClass繼承下了+(void)load而且可以被安全地當(dāng)做普通類方法(Class Method)被使用。這也就是我之前所說的load和initialize被調(diào)用一次是相對runtime而言。
同時,最后一個ChildClass調(diào)用+(void)load方法,其實是去調(diào)用父類的+(void)load方法
(比如SuperClass的initialize不會因為自身load方法調(diào)用一次,又因為子類調(diào)用了load又執(zhí)行一次),我們依然可以直接去反復(fù)調(diào)用這些方法。
3、子類的+(void)initialize會調(diào)用父類的+(void)initialize方法
修改代碼如下,去掉SuperClass中的+(void)load方法;讓ChildClass來重寫+(void)load,同時也去掉+(void)initialize。
在程序中不手動調(diào)用方法。
/******* Implementation *******/
@implementation SuperClass
+ (void) initialize {
NSLog(@"%@ %s", [self class], __FUNCTION__);
}
/**
+ (void) load {
NSLog(@"%@ %s", [self class], __FUNCTION__);
}
*/
@end
@implementation ChildClass
/**
+ (void) initialize {
NSLog(@"%@ %s", [self class], __FUNCTION__);
Insideinitialize * obj = [[Insideinitialize alloc] init];
[obj objectMethod];
}
*/
+ (void) load {
NSLog(@"%@ %s", [self class], __FUNCTION__);
}
@end
- (void)viewDidLoad {
[super viewDidLoad];
// [ChildClass load];
}
打印結(jié)果:

說明
和之前一樣,+(void)load會引起+(void)initialize。也很Apple文檔中講得那樣,子類方法的調(diào)用會激起父類的+(void)initialize被執(zhí)行。不過我們也看到雖然ChildClass沒有定義+(void)initialize,但是它會使用父類的+(void)initialize。而之前的示例,我們看到子類并不會在runtime時去使用父類的+(void)load,也就是說只有新定義的+(void)load才會被runtime去調(diào)用執(zhí)行。
4、類別中的+(void)load方法和+(void)initialize方法
新建一個類,同時增加兩個類別
.h
@interface MainClass : NSObject
@end
.m
/******* Category Implementation *******/
@implementation MainClass(Category)
+ (void) load {
NSLog(@"%@ %s", [self class], __FUNCTION__);
}
+ (void) initialize {
NSLog(@"%@ %s", [self class], __FUNCTION__);
}
@end
@implementation MainClass(OtherCategory)
+ (void) load {
NSLog(@"%@ %s", [self class], __FUNCTION__);
}
+ (void) initialize {
NSLog(@"%@ %s", [self class], __FUNCTION__);
}
@end
/******* Implementation *******/
@implementation MainClass
+ (void) load {
NSLog(@"%@ %s", [self class], __FUNCTION__);
}
+ (void) initialize {
NSLog(@"%@ %s", [self class], __FUNCTION__);
}
@end
打印結(jié)果:

說明
同樣的+(void)initialize優(yōu)先于+(void)load先執(zhí)行。但是很明顯的不同在于,只有最后一個類別(Category)的+(void)initialize執(zhí)行,其他兩個都被隱藏,這就是平常說的類別中的方法會“覆蓋”類中的方法。而對于+(void)load,三個都執(zhí)行,并且如果Apple的文檔中介紹順序一樣:先執(zhí)行類自身的實現(xiàn),再執(zhí)行類別(Category)中的實現(xiàn)。
5、不需要顯示使用super調(diào)用父類中的方法
/******* Category Implementation *******/
@implementation MainClass(Category)
+ (void) load {
[super load];
NSLog(@"%@ %s", [self class], __FUNCTION__);
}
+ (void) initialize {
[super initialize];
NSLog(@"%@ %s", [self class], __FUNCTION__);
}
@end
在調(diào)用+(void)load方法和+(void)initialize方法的時候,我們并不需要手動的寫入super的調(diào)用,默認(rèn)他會實現(xiàn)父類的調(diào)用,比如上個小節(jié)中ChildClass的+(void)initialize方法自動調(diào)用了SuperClass的+(void)initialize方法
總結(jié)
- +(void)load是只要類所在文件被引用就會被調(diào)用,是在main函數(shù)之前,而+(void)initialize是在類或者其子類的第一個方法被調(diào)用前調(diào)用。所以如果類沒有被引用進(jìn)項目,就不會有l(wèi)oad調(diào)用;但即使類文件被引用進(jìn)來,但是沒有使用,那么initialize 也不會被調(diào)用。+initialize的調(diào)用發(fā)生在+init方法之前。
- +(void)initialize只會被調(diào)用一次,Category中的+initialize方法會覆蓋類本身的+initialize方法,而在Category中+load方法卻不會覆蓋本身類中的+load 方法。如果父類中實現(xiàn)了+initialize方法,而子類中沒有重寫此方法,則子類初始化時就會使用父類的方法([super initialize])。
- runtime并不將類的+load方法作為類的第一個方法執(zhí)行,如果在+load方法里調(diào)用了類的方法([self class]),那么此時就會先調(diào)用類的+initialize方法。
- 如果子類沒有重寫+initialize方法,那么子類會自動的調(diào)用父類的+initialize方法,而子類沒有重寫+load方法,雖然子類繼承了父類的+load方法,但是系統(tǒng)并不會主動去調(diào)用父類+load方法,只有當(dāng)外界手動調(diào)用的時候才回去調(diào)用父類的方法。
- +(void)load方法在在類別中和類本身中都會調(diào)用,調(diào)用順序是先類,然后是類別,而+(void)initialize方法是只會調(diào)用類別中方法。
- +(void)load調(diào)用時機(jī)比較早,運(yùn)行環(huán)境有不確定因素。在App啟動時進(jìn)行加載,進(jìn)行l(wèi)oad調(diào)用的時候,并不能保證所有類都加載完成且可用,而且這個時候的autorelease pool還沒有創(chuàng)建出來,所以那些依賴autorelease pool的代碼都會有問題,這個時候就要自己負(fù)責(zé)做auto release處理,不要使用類方法創(chuàng)建對象,要用alloc創(chuàng)建對象然后做處理。