Objective-C——消息、Category和Protocol
Posted on 2012-10-17 13:49 為自己代言 閱讀(357) 評(píng)論(0) 編輯 收藏 所屬分類(lèi): iphone IOS 開(kāi)發(fā)想從JAVA轉(zhuǎn)到obj-c,看了些基礎(chǔ)的東西,感覺(jué)很奇怪,可能不太習(xí)慣,在網(wǎng)上看到一個(gè)不錯(cuò)文章有助理解obj-c的一些核心機(jī)制。
Objective-C——消息、Category和Protocol
2012-06-22 20:13 by 池建強(qiáng), 2627 閱讀, 11 評(píng)論, 收藏, 編輯
面向?qū)ο笥肋h(yuǎn)是個(gè)可以吐槽的話題,從開(kāi)始提出到推崇備至,到充滿(mǎn)質(zhì)疑,一路走來(lái)讓人唏噓不已。面向?qū)ο蟮乃枷肟芍^歷史悠久,20世紀(jì)70年代的Smalltalk可以說(shuō)是面向?qū)ο笳Z(yǔ)言的經(jīng)典,直到今天我們依然將這門(mén)語(yǔ)言視為面向?qū)ο笳Z(yǔ)言的基礎(chǔ)。
面向?qū)ο笫谴蟛糠志幊陶Z(yǔ)言的基本特性,像 C++、Java、Objective-C這樣的靜態(tài)語(yǔ)言,Ruby、Python這樣的動(dòng)態(tài)語(yǔ)言都是面向?qū)ο蟮恼Z(yǔ)言。但是如何編寫(xiě)面向?qū)ο蟮某绦騾s一直是困擾人們的話題,即使是Smalltalk,也有人認(rèn)為這是一個(gè)有缺陷的面向?qū)ο蟮恼Z(yǔ)言實(shí)現(xiàn)。
我在2010年翻譯過(guò)的一篇InfoQ的文章,《面向?qū)ο缶幊?#9472;─走錯(cuò)了路》中提到,面向?qū)ο缶幊痰娜齻€(gè)原則是:基于消息傳遞機(jī)制,對(duì)象分離和多態(tài)。文章中還舉了Erlang例子,認(rèn)為Erlang具備了這些原則,“所以可能是唯一的面向?qū)ο笳Z(yǔ)言”。除了之前提到的三個(gè)特征,單繼承和動(dòng)態(tài)類(lèi)型也被引用為面向?qū)ο笳Z(yǔ)言的“絕對(duì)需求”。基于這些考慮,文章指出,Smalltalk在實(shí)現(xiàn)對(duì)象思想時(shí)的“錯(cuò)誤”──例如,只關(guān)注狀態(tài)和行為,在類(lèi)和基于映像的語(yǔ)言里缺乏良好的并發(fā)模型和消息機(jī)制。
這篇文章中的核心就是,面向?qū)ο笏枷胫谐藢?duì)象的狀態(tài)、行為,還應(yīng)該關(guān)注其并發(fā)機(jī)制、消息機(jī)制,后者更為重要。這一點(diǎn)事實(shí)上是我在接觸了Objective-C之后才有了更深入的體會(huì)。
Ojbective-C的語(yǔ)法設(shè)計(jì)主要基于Smalltalk,除了提供傳統(tǒng)的面向?qū)ο缶幊烫匦灾猓€增加了很多類(lèi)似動(dòng)態(tài)語(yǔ)言Ruby、Python才具有的特性,例如動(dòng)態(tài)類(lèi)型、動(dòng)態(tài)加載、動(dòng)態(tài)綁定等等,同時(shí)強(qiáng)化了消息傳遞機(jī)制和表意(Intention Revealing Interface)接口的概念。
—消息—
消息傳遞模型(Message Passing)是Objective-C語(yǔ)言的核心機(jī)制。在Objective-C中,沒(méi)有方法調(diào)用這種說(shuō)法,只有消息傳遞。在C++或Java中調(diào)用某個(gè)類(lèi)的方法,在Objective-C中是給該類(lèi)發(fā)送一個(gè)消息。在C++或Java里,類(lèi)與類(lèi)的行為方法之間的關(guān)系非常緊密,一個(gè)方法必定屬于一個(gè)類(lèi),且于編譯時(shí)就已經(jīng)綁定在一起,所以你不可能調(diào)用一個(gè)類(lèi)里沒(méi)有的方法。而在Objective-C中就比較簡(jiǎn)單了,類(lèi)和消息之間是松耦合的,方法調(diào)用只是向某個(gè)類(lèi)發(fā)送一個(gè)消息,該類(lèi)可以在運(yùn)行時(shí)再確定怎么處理接受到的消息。也就是說(shuō),一個(gè)類(lèi)不保證一定會(huì)響應(yīng)接收到的消息,如果收到了一個(gè)無(wú)法處理的消息,那么程序就是簡(jiǎn)單報(bào)一個(gè)錯(cuò)。甚至你可以向一個(gè)值為nil的空對(duì)象發(fā)送消息,系統(tǒng)都不會(huì)出錯(cuò)或宕掉。這種設(shè)計(jì)本身也比較符合軟件的隱喻。
在表意接口(Intention Revealing Interface)方面,Objective-C也是設(shè)計(jì)的比較出色的語(yǔ)言。面向?qū)ο笳Z(yǔ)言的特性之一就是通過(guò)API把實(shí)現(xiàn)封裝起來(lái),為上層建筑提供服務(wù)。但是需要注意的一點(diǎn)就是,你封裝的API最好能夠讓調(diào)用者看到接口描述就知道怎么使用。如果為了使用一個(gè)API必須要去研究它的實(shí)現(xiàn),那么就失去了封裝的意義。Objective-C通過(guò)顯式的API描述,讓開(kāi)發(fā)者不自覺(jué)的寫(xiě)出滿(mǎn)足表意接口的API,比如下圖中的API描述。
上圖中描述了一個(gè)傳統(tǒng)意義的實(shí)例方法,但和Java或C++不同的是,其方法關(guān)鍵字由多個(gè)字符串組成,在這個(gè)例子是insertObject和atIndex,(id)anObject和 (NSUInterger)index分別表示參數(shù)類(lèi)型和參數(shù)名稱(chēng)。整個(gè)方法看上去就像一個(gè)英語(yǔ)句子,我們可以很容易的知道,這個(gè)方法就是在索引為 index處插入一個(gè)對(duì)象。如果你是從其他語(yǔ)言轉(zhuǎn)到Objective-C,那么開(kāi)始的時(shí)候會(huì)感覺(jué)這種寫(xiě)法有些繁復(fù),但是一旦理解并習(xí)慣了你會(huì)感受到其巨大的好處,這種寫(xiě)法會(huì)強(qiáng)制你寫(xiě)出優(yōu)美易讀的代碼和API,而且有了XCode強(qiáng)大的提示功能,再長(zhǎng)的方法也是一蹴而就。
下面我們來(lái)說(shuō)說(shuō)多態(tài)和繼承。
與Java一樣,Objective-C一樣不支持多重繼承,但是通過(guò)類(lèi)別(Category)和協(xié)議(Protocol)可以很好的實(shí)現(xiàn)代碼復(fù)用和擴(kuò)展。
—Category—
首先我們來(lái)談?wù)凜ategory。
Objective-C提供了一種與眾不同的方式——Catagory,可以動(dòng)態(tài)的為已經(jīng)存在的類(lèi)添加新的行為。這樣可以保證類(lèi)的原始設(shè)計(jì)規(guī)模較小,功能增加時(shí)再逐步擴(kuò)展。使用Category 對(duì)類(lèi)進(jìn)行擴(kuò)展時(shí),不需要訪問(wèn)其源代碼,也不需要?jiǎng)?chuàng)建子類(lèi)。Category使用簡(jiǎn)單的方式,實(shí)現(xiàn)了類(lèi)的相關(guān)方法的模塊化,把不同的類(lèi)方法分配到不同的分類(lèi)文件中。
實(shí)現(xiàn)起來(lái)很簡(jiǎn)單,我們舉例說(shuō)明。
SomeClass.h
@interface SomeClass : NSObject{
}
-(void) print;
@end
這是類(lèi)SomeClass的聲明文件,其中包含一個(gè)實(shí)例方法print。如果我們想在不修改原始類(lèi)、不增加子類(lèi)的情況下,為該類(lèi)增加一個(gè)hello的方法,只需要簡(jiǎn)單的定義兩個(gè)文件 SomeClass+Hello.h和SomeClass+Hello.m,在聲明文件和實(shí)現(xiàn)文件中用“()”把Category的名稱(chēng)括起來(lái)即可。聲明文件代碼如下:
#import "SomeClass.h"
@interface SomeClass (Hello)
-(void)hello;
@end
實(shí)現(xiàn)文件代碼如下
#import "SomeClass+Hello.h"
@implementationSomeClass (Hello)
-(void)hello{
NSLog (@"name:%@ ", @"Jacky");
}
@end
其中Hello是Category的名稱(chēng),如果你用XCode創(chuàng)建Category,那么需要填寫(xiě)的內(nèi)容包括名稱(chēng)和要擴(kuò)展的類(lèi)的名稱(chēng)。這里還有一個(gè)約定成俗的習(xí)慣,將聲明文件和實(shí)現(xiàn)文件名稱(chēng)統(tǒng)一采用“原類(lèi)名+Category”的方式命名。
調(diào)用也非常簡(jiǎn)單,毫無(wú)壓力,如下:
首先引入Category的聲明文件,然后正常調(diào)用即可。
#import "SomeClass+Hello.h"
SomeClass * sc =[[SomeClass alloc] init];
[sc hello]
執(zhí)行結(jié)果是:
name:Jacky
Category的使用場(chǎng)景:
1、當(dāng)你在定義類(lèi)的時(shí)候,在某些情況下(例如需求變更),你可能想要為其中的某個(gè)或幾個(gè)類(lèi)中添加方法。
2、一個(gè)類(lèi)中包含了許多不同的方法需要實(shí)現(xiàn),而這些方法需要不同團(tuán)隊(duì)的成員實(shí)現(xiàn)
3、當(dāng)你在使用基礎(chǔ)類(lèi)庫(kù)中的類(lèi)時(shí),你可能希望這些類(lèi)實(shí)現(xiàn)一些你需要的方法。
遇到以上這些需求,Category可以幫助你解決問(wèn)題。當(dāng)然,使用Category也有些問(wèn)題需要注意,
1、Category可以訪問(wèn)原始類(lèi)的實(shí)例變量,但不能添加變量,如果想添加變量,可以考慮通過(guò)繼承創(chuàng)建子類(lèi)。
2、Category可以重載原始類(lèi)的方法,但不推薦這么做,這么做的后果是你再也不能訪問(wèn)原來(lái)的方法。如果確實(shí)要重載,正確的選擇是創(chuàng)建子類(lèi)。
3、和普通接口有所區(qū)別的是,在分類(lèi)的實(shí)現(xiàn)文件中可以不必實(shí)現(xiàn)所有聲明的方法,只要你不去調(diào)用它。
用好Category可以充分利用Objective-C的動(dòng)態(tài)特性,編寫(xiě)出靈活簡(jiǎn)潔的代碼。
—Protocol—
下面我們?cè)賮?lái)看Protocol。
Protocol,簡(jiǎn)單來(lái)說(shuō)就是一系列不屬于任何類(lèi)的方法列表,其中聲明的方法可以被任何類(lèi)實(shí)現(xiàn)。這種模式一般稱(chēng)為代理(delegation)模式。你通過(guò)Protocol定義各種行為,在不同的場(chǎng)景采用不同的實(shí)現(xiàn)方式。在iOS和OS X開(kāi)發(fā)中,Apple采用了大量的代理模式來(lái)實(shí)現(xiàn)MVC中View和Controller的解耦。
定義Protocol很簡(jiǎn)單,在聲明文件(h文件)中通過(guò)關(guān)鍵字@protocol定義,然后給出Protocol的名稱(chēng),方法列表,然后用@end表示Protocol結(jié)束。在@end指令結(jié)束之前定義的方法,都屬于這個(gè)Protocol。例如:
@protocol ProcessDataDelegate <NSObject>
@required
- (void) processSuccessful: (BOOL)success;
@optional
- (id) submitOrder: (NSNumber *) orderid;
@end
以上代碼可以單獨(dú)放在一個(gè)h文件中,也可以寫(xiě)在相關(guān)類(lèi)的h文件中,可以視具體情況而定。該P(yáng)rotocol包含兩個(gè)方法,processSuccessful和submitOrder。這里還有兩個(gè)關(guān)鍵字,@required和@optional,表示如果要實(shí)現(xiàn)這個(gè)協(xié)議,那么processSuccessful方法是必須要實(shí)現(xiàn)的,submitOrder則是可選的,這兩個(gè)注解關(guān)鍵字是在Objective-C 2.0之后加入的語(yǔ)法特性。如果不注明,那么方法默認(rèn)是@required的,必須實(shí)現(xiàn)。
那么如何實(shí)現(xiàn)這個(gè)Protocol呢,很簡(jiǎn)單,創(chuàng)建一個(gè)普通的Objective-C類(lèi),取名為T(mén)estAppDelegate,這時(shí)會(huì)生成一個(gè)h文件和m文件。在h文件中引入包含Protocol的h文件,之后聲明采用這個(gè)Protocol即可,如下:
@interface TestAppDelegate : NSObject<ProcessDataDelegate>;
@end
用尖括號(hào)(<...>)括起來(lái)的ProcessDataDelegate就是我們創(chuàng)建的Protocol。如果要采用多個(gè)Protocol,可以在尖括號(hào)內(nèi)引入多個(gè)Protocol 名稱(chēng),并用逗號(hào)隔開(kāi)即可。例如<ProcessDataDelegate,xxxDelegate>
m文件如下:
@implementation TestAppDelegate
- (void) processSuccessful: (BOOL)success{
if (success) {
NSLog(@"成功");
}else {
NSLog(@"失敗");
}
}
@end
由于submitOrder方法是可選的,所以我們可以只實(shí)現(xiàn)processSuccessful。
Protocol一般使用在哪些場(chǎng)景呢?Objective-C里的Protocol和Java語(yǔ)言中的接口很類(lèi)似,如果一些類(lèi)之間沒(méi)有繼承關(guān)系,但是又具備某些相同的行為,則可以使用 Protocol來(lái)描述它們的關(guān)系。不同的類(lèi),可以遵守同一個(gè)Protocol,在不同的場(chǎng)景下注入不同的實(shí)例,實(shí)現(xiàn)不同的功能。其中最常用的就是委托代理模式,Cocoa框架中大量采用了這種模式實(shí)現(xiàn)數(shù)據(jù)和UI的分離。例如UIView產(chǎn)生的所有事件,都是通過(guò)委托的方式交給Controller完成。根據(jù)約定,框架中后綴為Delegate的都是Protocol,例如UIApplicationDelegate,UIWebViewDelegate 等,使用時(shí)大家可以留意一下,體會(huì)其用法。
使用Protocol時(shí)還需要注意的是:
1、Protocol本身是可以繼承的,比如:
@protocol A
-(void)methodA;
@end
@protocol B <A>
-(void)methodB;
@end
如果你要實(shí)現(xiàn)B,那么methodA和methodB都需要實(shí)現(xiàn)。
2、Protocol是類(lèi)無(wú)關(guān)的,任何類(lèi)都可以實(shí)現(xiàn)定義好的Protocol。如果我們想知道某個(gè)類(lèi)是否實(shí)現(xiàn)了某個(gè)Protocol,還可以使用conformsToProtocol進(jìn)行判斷,如下:
[obj conformsToProtocol:@protocol(ProcessDataDelegate)]
好吧,具體的語(yǔ)言特性這次就介紹這么多。從某種意義上來(lái)說(shuō),Objective-C是一門(mén)古老的語(yǔ)言,發(fā)明于1980年。1988年,喬布斯的Next公司獲得了Objective-C語(yǔ)言的授權(quán),并開(kāi)發(fā)出了Objective-C的語(yǔ)言庫(kù)和NEXTSTEP的開(kāi)發(fā)環(huán)境。NextStep是以Mach和BSD為基礎(chǔ),Objective-C是其語(yǔ)言和運(yùn)行庫(kù),后來(lái)的事大家都清楚,蘋(píng)果買(mǎi)了Next,喬布斯回歸蘋(píng)果,開(kāi)始神奇的蘋(píng)果振興之路,NextStep成了Max OS X的基礎(chǔ)。以后發(fā)展越來(lái)越好,Objctive-C成了Apple的當(dāng)家語(yǔ)言,現(xiàn)在基本上是Apple在維護(hù)Objctive-C的發(fā)展。
在蘋(píng)果的AppStore推出之前,Objective-C一直相對(duì)小眾,但是其優(yōu)秀的語(yǔ)言特性似乎一直在為后面的爆發(fā)積蓄力量,當(dāng)蘋(píng)果平臺(tái)級(jí)的應(yīng)用出現(xiàn)之后,Objective-C開(kāi)始大放異彩,靜態(tài)語(yǔ)言的效率和動(dòng)態(tài)語(yǔ)言的特性得到眾多程序員的喜愛(ài),目前它已經(jīng)以火箭般的速度躥升TIOBE語(yǔ)言排行版第四位。
對(duì)于喜愛(ài)蘋(píng)果技術(shù)的技術(shù)人員來(lái)說(shuō),Objective-C是你必須深入了解和值得學(xué)習(xí)的一門(mén)語(yǔ)言,希望以后有機(jī)會(huì)多寫(xiě)一些相關(guān)的文章。
轉(zhuǎn)載于:http://www.cnblogs.com/chijianqiang/archive/2012/06/22/objc-category-protocol.html
轉(zhuǎn)載于:http://www.cnblogs.com/chijianqiang/archive/2012/06/22/objc-category-protocol.html