Objective-C入門(mén)學(xué)習(xí)基礎(chǔ) 類(lèi)聲明和定義
Objective-C入門(mén)學(xué)習(xí)基礎(chǔ) 類(lèi)聲明和定義是本文要介紹的內(nèi)容,很詳細(xì)的為友們介紹Objective-C學(xué)習(xí)基礎(chǔ),不多說(shuō)我們先來(lái)看內(nèi)容。
編譯處理指令
既然Objective-C是面向?qū)ο蟮某绦蛘Z(yǔ)言,所以理應(yīng)支持可重用的數(shù)據(jù)和函數(shù)的封裝體,即類(lèi)。
類(lèi)是在結(jié)構(gòu)體的基礎(chǔ)上發(fā)展的產(chǎn)物,結(jié)構(gòu)體只能處理數(shù)據(jù),在結(jié)構(gòu)體之上增加對(duì)該數(shù)據(jù)處理的函數(shù),就構(gòu)成類(lèi)的概念。類(lèi)使程序總能提供對(duì)數(shù)據(jù)專(zhuān)門(mén)處理函數(shù)的安全調(diào)用,使得一系列的機(jī)能作為一個(gè)子系統(tǒng)供安全且重復(fù)的使用。
像結(jié)構(gòu)體一樣,類(lèi)在使用之前必須先聲明,但是Objective-C并沒(méi)有像其他面向?qū)ο笳Z(yǔ)言那樣提供聲明類(lèi)的專(zhuān)用關(guān)鍵字或者語(yǔ)法,而是用編譯處理指令來(lái)實(shí)現(xiàn),特征是類(lèi)聲明語(yǔ)句都須以@符號(hào)開(kāi)始。
類(lèi)聲明的編譯處理指令以@interface開(kāi)始,以@end結(jié)尾,在這之間代碼便是類(lèi)變量的定義和方法的聲明。類(lèi)的聲明和定義比其他語(yǔ)言復(fù)雜,這會(huì)讓剛開(kāi)始學(xué)習(xí)Objective-C的人非常困惑(準(zhǔn)確的說(shuō),其他語(yǔ)言如Java只需定義類(lèi)而不用聲明,而Objective-C需要先聲明再定義)。
- @interface 類(lèi)名 : 父類(lèi)名
- {
- 實(shí)例變量定義
- ...
- }
- 方法聲明
- @end
這就是Objective-C類(lèi)聲明的語(yǔ)法結(jié)構(gòu),其中實(shí)例變量是供類(lèi)內(nèi)部使用的變量,和結(jié)構(gòu)體的成員變量相似,但是實(shí)例變量不能從類(lèi)的外部使用,原則上只能被類(lèi)內(nèi)部的方法使用(當(dāng)然只是原則上)。類(lèi)可以沒(méi)有實(shí)例變量,這時(shí){}可以省略。
類(lèi)的方法(注意和類(lèi)方法的區(qū)別)是專(zhuān)屬該類(lèi)的方法,與普通函數(shù)的區(qū)別是:類(lèi)的方法可以操作類(lèi)內(nèi)部的實(shí)例變量。
緊接類(lèi)名后邊的是父類(lèi)名,也就是說(shuō)可以指定類(lèi)的父類(lèi),構(gòu)成繼承。繼承使類(lèi)可繼承使用父類(lèi)的機(jī)能,而僅定義父類(lèi)沒(méi)有的機(jī)能。比如父類(lèi)是抽象的哺乳動(dòng)物類(lèi),如果定義貓類(lèi)的時(shí)候,可以繼承哺乳動(dòng)物這個(gè)父類(lèi),而在貓類(lèi)中只定義貓區(qū)別與普通哺乳動(dòng)物類(lèi)的特有功能即可。
父類(lèi)可以不指定,這時(shí)編譯器會(huì)為類(lèi)提供一個(gè)缺省的類(lèi),即根類(lèi)。
Objective-C的根類(lèi)隨具體編譯器的不同而有所不同,GCC編譯器中是Object,Mac OS X的Cocoa編譯環(huán)境中則是NSObject,除非自己開(kāi)發(fā)根類(lèi)時(shí)可以不指定父類(lèi),一般情況下都要采用系統(tǒng)提供的根類(lèi)作為父類(lèi)。僅在根類(lèi)開(kāi)發(fā)時(shí),類(lèi)的定義可以如下(沒(méi)有父類(lèi)):
- @interface 類(lèi)名
- {
- 實(shí)例變量聲明
- ...
- }
類(lèi)方法聲明
- @end
為什么所有的類(lèi)都必須繼承自一個(gè)共同的根類(lèi),那是因?yàn)楦?lèi)提供了類(lèi)正常動(dòng)作所必須的一些基本機(jī)能,比如內(nèi)存的取得和釋放,如果沒(méi)有根類(lèi),那么所有的類(lèi)都要自己去完成這些基本的工作,會(huì)使類(lèi)非常的復(fù)雜而不能專(zhuān)注于具體業(yè)務(wù)(后面還會(huì)具體說(shuō)明)。
類(lèi)中實(shí)例變量的聲明和普通C語(yǔ)言的變量聲明沒(méi)有什么區(qū)別,但是類(lèi)方法的聲明則差別很大,語(yǔ)法如下:
-(返回值類(lèi)型) 方法名 : 臨時(shí)參數(shù)列…;
首先,最左邊的減號(hào),代表該方法是類(lèi)的實(shí)例方法,如果是加號(hào)則代表該方法為類(lèi)方法。這里須記住一點(diǎn):普通定義類(lèi)的時(shí)候,方法前用減號(hào)即實(shí)例方法即可,類(lèi)方法是可以不用生成實(shí)例而直接調(diào)用的方法。實(shí)例方法和類(lèi)方法的區(qū)別后面會(huì)詳細(xì)說(shuō)明。
其次,返回值類(lèi)型要放在()中,如果函數(shù)需要參數(shù)的時(shí)候,參數(shù)的類(lèi)型也要放到()中,然后緊接參數(shù)名,如果有多個(gè)參數(shù),則用逗號(hào)隔開(kāi)。
C語(yǔ)言函數(shù)的缺省返回值類(lèi)型是int型,在Objective-C中新追加了一個(gè)id型的對(duì)象類(lèi)型作為缺省函數(shù)的返回值類(lèi)型。雖然返回值可以不指定,但一般不建議這么做。如果沒(méi)有返回值,則要用(void)做明確說(shuō)明。
- @interface Test : Object
- (void)method;
- @end
在這個(gè)Test類(lèi)聲明中,聲明了一個(gè)沒(méi)有返回值,沒(méi)有參數(shù)的方法method,類(lèi)和方法以及變量的命名規(guī)則和C語(yǔ)言一樣,以字母或下劃線開(kāi)頭。但是習(xí)慣上類(lèi)名的首字母大寫(xiě),方法名則全部小寫(xiě)。
到這里,類(lèi)的聲明已經(jīng)做好了,但是方法method只是聲明了名稱(chēng)和類(lèi)型,具體實(shí)現(xiàn)的代碼怎么寫(xiě)呢?事實(shí)上,Objective-C將類(lèi)的聲明和定義完全分開(kāi),在類(lèi)的聲明中,只能定義實(shí)例變量和方法名及類(lèi)型,具體的實(shí)現(xiàn)要用到@implementation這個(gè)編譯處理指令中進(jìn)行。
- @implementation 類(lèi)名
實(shí)例方法定義
- @end
- @implementation
這個(gè)編譯指令具體定義@interface中聲明的方法,聲明過(guò)的方法,必須在這里具體定義。
類(lèi)的實(shí)例化
類(lèi)經(jīng)過(guò)聲明和定義,但是還不能直接使用,使用類(lèi)之前必須分配具體的內(nèi)存領(lǐng)域且進(jìn)行適當(dāng)?shù)某跏蓟8鶕?jù)類(lèi)的聲明具體分配一塊內(nèi)存,這個(gè)過(guò)程叫實(shí)例化,而具體分配的這塊內(nèi)存,叫做實(shí)例或者對(duì)象。
C++或者Java中為我們提供好了new運(yùn)算符,可以自動(dòng)由類(lèi)生成實(shí)例并完成初始化,而Objective-C實(shí)例化竟然也要類(lèi)自己完成(即需要類(lèi)給出實(shí)例化自己的方法)。實(shí)例化需要調(diào)查生成對(duì)象的大小,申請(qǐng)內(nèi)存完成復(fù)雜的初始化,這些任務(wù)對(duì)普通用戶(hù)太難了,不過(guò)幸好編譯環(huán)境為我們提供了根類(lèi)(Object)來(lái)幫助完成這些功能,這也是為什么所有的類(lèi)都必須繼承自根類(lèi)的原因(否則實(shí)例化方法要自己寫(xiě))。
在根類(lèi)Object中,定義了實(shí)例化根類(lèi)以及繼承自根類(lèi)的類(lèi)的類(lèi)方法alloc,一般的實(shí)例方法,必須先有實(shí)例才能調(diào)用,但是類(lèi)方法,沒(méi)有實(shí)例也可以使用。所以類(lèi)方法alloc雖然沒(méi)有實(shí)例,也是可以正常調(diào)用的。鑒于alloc是用來(lái)生成實(shí)例的類(lèi)方法,所以也常常也被稱(chēng)作工廠方法。
- +alloc;
這是Object中alloc的聲明,+開(kāi)頭,說(shuō)明是一個(gè)類(lèi)方法,缺省返回值為id類(lèi)型,沒(méi)有參數(shù)。
id型是代表對(duì)象的廣義類(lèi)型,什么類(lèi)型的對(duì)象都可以放入id型的對(duì)象中。
下面,就要調(diào)用alloc類(lèi)方法,生成實(shí)例了,但是怎樣寫(xiě)呢?如果熟悉C++,可能會(huì)首先想到下面的調(diào)用方式:
- id obj =類(lèi)名.alloc();
遺憾的是,這種寫(xiě)法是錯(cuò)誤的,和大多數(shù)面向?qū)ο笳Z(yǔ)言的調(diào)用方式不同,Objective-C有自己獨(dú)特的調(diào)用方式:
- [類(lèi)名 類(lèi)方法名:參數(shù)序列...]
如果是調(diào)用實(shí)例方法的時(shí)候,要將類(lèi)名換成實(shí)例名,其中[ ]在Objective-C中被稱(chēng)為消息,這是因?yàn)樵贠bjective-C中,從對(duì)象調(diào)用方法的時(shí)候,不是直接調(diào)用,而是向?qū)ο蟀l(fā)送特定的消息,對(duì)象接收到消息后,根據(jù)消息內(nèi)容啟動(dòng)相應(yīng)的方法,這種方式雖然帶來(lái)了程序的柔軟性,但是比C語(yǔ)言的調(diào)用方式帶來(lái)額外的消耗,因?yàn)槌绦驁?zhí)行時(shí)要耗費(fèi)時(shí)間檢索特定的方法然后啟動(dòng)。
- #import <stdio.h>
- #import <objc/Object.h>
- @interface Test : Object
- - (void)method;
- @end
- @implementation Test
- - (void)method {
- printf("Kitty on your lap\n");
- }
- @end
- int main() {
- id obj = [Test alloc];
- [obj method];
- return 0;
- }
上面的程序是一個(gè)Objective-C簡(jiǎn)單但完整的類(lèi)實(shí)例例子,@interface完成類(lèi)的聲明,繼承自根類(lèi)Object。@implementation完成類(lèi)的定義,具體定義method的實(shí)現(xiàn)方法。
類(lèi)聲明和定義準(zhǔn)備好之后,在main函數(shù)中,首先定義id型的對(duì)象變量obj,然后調(diào)用Test類(lèi)的父類(lèi)Object的類(lèi)方法alloc生成實(shí)例,***調(diào)用實(shí)例obj的實(shí)例方法method,實(shí)現(xiàn)輸出打印。
另外,如果不定義obj變量(或者說(shuō)Test的實(shí)例只在這里使用一次就不用了),也可以像下面的寫(xiě)法:
- [[Test alloc] method]
注:像上面的程序片段一樣,雖然對(duì)類(lèi)的聲明和定義的具體位置沒(méi)有要求,但是習(xí)慣上把類(lèi)的聲明放到頭文件中,類(lèi)的定義放到和類(lèi)名同名的.m文件中。
原帖發(fā)布地址(PDF版): http://bbs.goocnjp.com/thread-338.html
小結(jié):關(guān)于Objective-C入門(mén)學(xué)習(xí)基礎(chǔ) 類(lèi)聲明和定義的內(nèi)容介紹完了,希望本文對(duì)你有所幫助!