標籤:
好了,我們在這裡總結一下,類的定義方法如下:
@interface類的名字:父類的名字{ 實體變數類型實體變數名字;
...
}
-(傳回值類型)方法名字;
+(傳回值類型)方法名字;
-(傳回值類型)方法名字:(變數類型)變數名字標籤1:(變數類型)變數1名字;
...
@end
“Cattle.m”檔案: #import"Cattle.h" @implementationCattle -(void)saySomething { NSLog(@"Hello,Iamacattle,Ihave%dlegs.",legsCount); } -(void)setLegsCount:(int)count 10{ legsCount=count; } @end
我們來看第4行和第13行,和標頭檔裡面的@一樣,我們這裡類的定義也是使用的編譯導向。編譯器會把從@implementation到@end之間的部分看作是類的定義。@implementation的後面有一個空格,空格的後面是我們的類的名字Cattle,這是在告訴編譯器,我們要定義Cattle類了。第4行和第13行之間是我們在標頭檔裡面定義的實體方法或者類方法的定義部分,當然我們的類如果沒有任何的實體方法和類方法的話,我們也許要寫上@implementation和@end,把中間留為空白就可以了。
第5行是我們定義的saySomething的實現,我們可以發現第5行的內容和標頭檔Cattle.h的第7行是一致的。筆者個人認為在編寫實體方法和類方法的定義的時候,為了避免手工輸入產生的誤差,可以從標頭檔當中把聲明的部分拷貝過來,然後刪除掉分號,加上兩個花括弧。我們知道地6行到第8行是方法的定義的部分,我們再來看看第7行。第7行和第二章的Hello,World輸出有些相似,只不過多了一個%d,還有實體變數legsCount,這個寫法和C語言裡面的printf是類似的,輸出的時候會使用legsCount來替代字串裡面的%d。
第9行的內容和Cattle.h的第8行一致的,這個不需要再解釋了。我們來看看第11行,第11行是在說,把參數count的數值賦值給實體變數legsCount。我們可以通過使用setLegsCount方法來控制Cattle對象裡面legsCount的數值。
這部分內容的關鍵點為@implementation和@end,理解了這個東西,其餘的就不難理解了。我們來總結一下,類的定義部分的文法:
@implementation類的名字 -(方法傳回值)方法名字 {
方法定義 }
-(方法傳回值)方法名字:(變數類型)變數名字 {
方法定義 } @end
1 #import<Foundation/Foundation.h> 2 3 #import"Cattle.h" 4 5 intmain(intargc,constchar*argv[]) 6 { 7 8 NSAutoreleasePool*pool=[[NSAutoreleasePoolalloc]init]; 9 10 idcattle=[Cattlenew]; 11 12 [cattlesetLegsCount:4]; 13 14 [cattlesaySomething]; 15 16 [pooldrain]; 17 18 return0; 19 20 }
同學們請看第10行的第一個單詞id。id是英文identifier的縮寫,我們在很多地方都遇到過id,比如說在部落格園裡面,我們都使用id來登陸系統的,我們的id就代表著系統的一個使用者。由於id在一個系統當中是唯一的,所以系統獲得我們的id之後就知道我們是誰了。Objective-C也是一樣的道理,使用id來代表一個對象,在Objective-C當中,所有的對象都可以使用id來進行區分。我們知道一個類僅僅是一些資料外加上操作這些資料的代碼,所以id實際上是指向資料結構的一個指標而已,相當於void*。
第10行的第二個單詞是cattle,就是我們給這個id起的一個名字。當然,你可以起系統保留的名字以外的任何名字,不過為了維持代碼的可讀性,我們需要一個有意義的名字,我們這裡使用頭文字為小寫cattle。
第10行的[Cattlenew]是建立對象,new實際上是alloc和init的組合,在Objective-C裡面建立對象是一個為對象分配記憶體和初始化的過程。new,alloc還有init定義在Cattle的超類NSObject裡面,筆者將要在第7章裡面詳細的解釋一下如何建立對象。在第7章之前我們都是用new來建立對象。
Objective-C裡面的方法的使用和其他語言有些不同,Objective-C使用訊息(Message)來調用方法。所以筆者認為在講解第7行等號右邊的部分之前,需要首先向大家介紹一個我們的新朋友,訊息(Message)。所謂的訊息就是一個類或者對象可以執行的動作。訊息的格式如下:
[對象或者類名字方法名字:參數序列]; 首先我們觀察到有兩個中括弧,最右邊的括弧之後是一個分號,當編譯器遇到了這個格式之後會把中間的部分當作一個訊息來發送。在上文的運算式當中,包括中括弧的所有部分的內容被稱作訊息運算式(Messageexpression),“對象或者類名字”被稱作接收器(Receiver),也就是訊息的接受者,“方法名字:參數序列”被稱為一個訊息(Message),“方法名字”被稱作選取器(Selector)或者關鍵字(Keyword)。Objective-C和C語言是完全相容的,C語言裡面的中括弧用於表示數組,但是數組的格式明顯和訊息的發送的格式是不一樣的,所以我們可以放心,編譯器不會把我們的訊息發送當作一個數組。
我們來回憶一下C語言裡面函數的調用過程,實際上編譯器在編譯的時候就已經把函數相對於整個執行包的入口地址給確定好了,函數的執行實際上就是直接從這個地址開始執行的。Objective-C使用的是一種間接的方式,Objective-C向對象或者類(具體上是對象還是類的名字取決於方法是實體方法還是類方法)發送訊息,訊息的格式應該和方法相同。具體來說,第7行等號右邊的部分[Cattlenew]就是說,向Cattle類發送一個new的訊息。這樣當Cattle類接收到new的時候,就會尋找它可以相應的訊息的列表,找到了new之後就會調用new的這個類方法,分配記憶體和初始化完成之後返回一個id,這樣我們就得到一個對象。
子類Subclass和超類Superclass
@interfaceCattle:NSObject{
這段代碼是在告訴編譯器,我們的Cattle是繼承的NSObject。在這段代碼當中,NSObject是超類,Cattle是子類。通過這樣寫,我們曾經免費的得到了NSObject裡面的一個方法叫做new:()
idcattle=[Cattlenew];
- 在物件導向的程式設計當中,如果在子類當中繼承了超類的話,那麼超類當中已經生效的部分代碼在子類當中仍然是有效,這樣就大大的提高了代碼的效率。基於超類我們可以把我們需要追加的一些功能放到子類裡面去,在本章裡面,我們決定基於Cattle類,重建一個子類Bull:
1 #import<Foundation/Foundation.h> 2 #import"Cattle.h" 3 @interfaceBull:Cattle 4 { 5 NSString*skinColor; 6 } 7 -(void)saySomething; 8 -(NSString*)getSkinColor; 9 -(void)setSkinColor:(NSString*)color; 10 @end
上段代碼裡面的第2行,是通知編譯器,我們這個類的聲明部分需要Cattle.h檔案。這個檔案我們已經很熟悉了,是我們在第3章曾經構築過的,在本章裡面,我們不會改變裡面的任何內容。
第4行,就是在通知編譯器,我們需要聲明一個類名字叫做Bull,從Cattle裡面繼承過來。 第5行,我們追加了一個執行個體變數skinColor,用來儲存Bull的顏色。
第7行,我們重載了在Cattle類裡面已經有的(void)saySomething執行個體方法。重載(void)saySomething方法的主要原因是,我們認為Bull說的話應該和Cattle有所區別。 第8行到第9行,我們為Bull類聲明了兩個新的方法(NSString*)getSkinColor和
(void)setSkinColor:(NSString*)color,分別用來設定和讀取我們的執行個體變數skinColor。 好的,我們總結一下繼承的時候的子類的格式。
@interface類的名字:父類的名字{ 實體變數類型實體變數名字;} -(傳回值類型)重載的方法名字; +(傳回值類型)重載的方法名字; -(傳回值類型)其他的方法名字:(變數類型)變數名字:(變數類型)變數名字; @end
Objective-C入門教程(摘錄)