Objective-C很有趣的一個(gè)地方是颁股,它非常非常像C星著。實(shí)際上特笋,它就是C語(yǔ)言加上一些其他擴(kuò)展和一個(gè)運(yùn)行時(shí)間(runtime)。
有了這個(gè)在每個(gè)Objective-C程序中都會(huì)起作用的附加運(yùn)行時(shí)間拢切,給了它一些動(dòng)態(tài)的特性蒂萎。C和C++沒(méi)有運(yùn)行時(shí)間,他們僅僅被編譯為完全按照代碼的順序去執(zhí)行淮椰,不多也不少五慈。
Objective-C中帶有運(yùn)行時(shí)間的好處是,它可以在你的程序運(yùn)行的流程中進(jìn)行參與主穗。在Objective-C中泻拦,它包括檢查是否一個(gè)對(duì)象可以處理特定的消息,如果不能處理忽媒,它就幫助你自動(dòng)調(diào)用其他特定的方法去完成争拐。
initialize不是init
運(yùn)行時(shí)間的行為之一就是initialize。雖然看起來(lái)有點(diǎn)像大家常見(jiàn)的init晦雨,但是他們并不相同架曹。
在程序運(yùn)行過(guò)程中,它會(huì)在你程序中每個(gè)類(lèi)調(diào)用一次initialize金赦。這個(gè)調(diào)用的時(shí)間發(fā)生在你的類(lèi)接收到消息之前,但是在它的超類(lèi)接收到initialize之后对嚼。
舉個(gè)例子夹抗,比如一個(gè)叫做Duck的類(lèi):
#import "Duck.h";
@implementation Duck
+(void) initialize {
NSLog(@"Duck initialize");
}
-(void) init {
NSLog(@"Duck init");
}
@end
我們?cè)谶@里記錄initialize和init調(diào)用的時(shí)間。
我們建立三個(gè)Duck對(duì)象的實(shí)例:
NSLog(@"Hello, World!");
Duck* duck1 = [[Duck alloc] init];
Duck* duck2 = [[Duck alloc] init];
Duck* duck3 = [[Duck alloc] init];
看一下記錄:
[Session started at 2008-03-23 20:03:25 -0400.]
2008-03-23 20:03:25.869 initialize_example[30253:10b] Hello, World!
2008-03-23 20:03:25.871 initialize_example[30253:10b] Duck initialize
2008-03-23 20:03:25.872 initialize_example[30253:10b] Duck init
2008-03-23 20:03:25.873 initialize_example[30253:10b] Duck init
2008-03-23 20:03:25.873 initialize_example[30253:10b] Duck init
我們可以看到纵竖,雖然我們創(chuàng)建了3個(gè)Duck的實(shí)例漠烧,但是initialize僅僅被調(diào)用了一次。我們也可以看到靡砌,直到我們創(chuàng)建了一個(gè)Duck的實(shí)例已脓,initialize才被調(diào)用。
但是如果Duck有一個(gè)子類(lèi)的話(huà)通殃,比如我們建一個(gè)Duck的子類(lèi)叫做Chicken(好怪異……)
#import <cocoa/Cocoa.h>
#import "Duck.h"
@interface Chicken : Duck {
}
@end
注意Chicken這個(gè)類(lèi)并沒(méi)有實(shí)現(xiàn)initialize方法度液。
如果我們同樣運(yùn)行這個(gè)程序,但是加上一個(gè)Chicken的實(shí)例:
NSLog(@"Hello, World!");
Duck* duck1 = [[Duck alloc] init];
Duck* duck2 = [[Duck alloc] init];
Duck* duck3 = [[Duck alloc] init];
Chicken* chicken = [[Chicken alloc] init];
我們期待看到4個(gè)Duck的init調(diào)用(因?yàn)槲覀兘⒘?個(gè)Duck和一個(gè)Chicken)画舌,但是我們看到了這樣情況:
[Session started at 2008-03-23 20:13:34 -0400.]
2008-03-23 20:13:34.696 initialize_example[30408:10b] Hello, World!
2008-03-23 20:13:34.698 initialize_example[30408:10b] Duck initialize
2008-03-23 20:13:34.699 initialize_example[30408:10b] Duck init
2008-03-23 20:13:34.700 initialize_example[30408:10b] Duck init
2008-03-23 20:13:34.700 initialize_example[30408:10b] Duck init
2008-03-23 20:13:34.700 initialize_example[30408:10b] Duck initialize
2008-03-23 20:13:34.701 initialize_example[30408:10b] Duck init
我們看到了4個(gè)Duck的init和2個(gè)Duck的initialize方法堕担。這是怎么回事呢?
看來(lái)如果一個(gè)子類(lèi)沒(méi)有實(shí)現(xiàn)initialize方法曲聂,那么超類(lèi)會(huì)調(diào)用這個(gè)方法兩次霹购,一次為自己,而一次為子類(lèi)朋腋。
我們?cè)贒uck的initialize類(lèi)中記錄一下類(lèi)名齐疙,這樣可以看得更清楚:
+(void) initialize {
NSLog(@"Duck initialize class:%@",[self class]);
}
現(xiàn)在看明白了:
[Session started at 2008-03-23 20:21:08 -0400.]
2008-03-23 20:21:08.816 initialize_example[30513:10b] Hello, World!
2008-03-23 20:21:08.818 initialize_example[30513:10b] Duck initialize class:Duck
2008-03-23 20:21:08.819 initialize_example[30513:10b] Duck init
2008-03-23 20:21:08.820 initialize_example[30513:10b] Duck init
2008-03-23 20:21:08.820 initialize_example[30513:10b] Duck init
2008-03-23 20:21:08.820 initialize_example[30513:10b] Duck initialize class:Chicken
2008-03-23 20:21:08.821 initialize_example[30513:10b] Duck init
如果你希望確定只用了initialize一次用來(lái)實(shí)現(xiàn)某些單獨(dú)運(yùn)行的工作膜楷,或者希望實(shí)現(xiàn)僅僅運(yùn)行一次的方法,檢查一下[self class]贞奋,才能確定是否是你希望做到的效果赌厅。