天天看點

Objective-C 協定(protocol)

協定(protocol)是Objective-c中一個非常重要的語言特性,從概念上講,非常類似于JAVA中接口. 一個協定其實就是一系列有關聯的方法的集合(為友善後面叙述,我們把這個協定命名為myProtocol)。協定中的方法并不是由協定本身去實作,相反而是由遵循這個協定的其他類來實作。換句話說,協定myProtocol隻是完成對協定函數的聲明而并不管這些協定函數的具體實作。

聲明一個協定的文法非常簡單:

@protocol myProtocol <NSObject>  

@required  

-(void) protocolNameA:(NSString*)string;  

@optional  

-(void) protocolNameB:(NSString*)string;  

@end  

第一行是聲明這個協定的名字為myProtocol。尖括号中的NSObject本身也是一個協定,其中定義了很多基本的協定函數,比如performSelector,isKindOfClass,respondsToSelector,conformsToProtocol,retain,release等。

協定接口分為required和optional兩類。required顧名思義是說遵守這個協定的那個類“必須要”實作的接口,而optional則是可以實作也可以不實作的。協定接口的定義和普通的函數定義是一樣的。

最後一行@end表示協定定義結束。這個協定的定義通常是在.h檔案中。

定義一個類遵循這個協定:

@interface myClass  <myProtocol>  

@interface myClass :NSObject<myProtocol>  

@interface myClass :NSObject<myProtocol, NSCoding>  

上面分别是三種不同的情況。編譯的時候編譯器會自動檢查myClass是否實作了myProtocol中的必要的(@required)接口。如果沒有實作則會發出一個警告資訊。另外需要注意的是,如果有繼承自myClass的子類,這些子類也是會自動遵循myClass所遵循的協定的,而且也可以重載這些接口。

為什麼需要協定?

To declare methods that others are expected to implement

To declare the interface to an object while concealing its class

To capture similarities among classes that are not hierarchically related

其實還有第四個很重要的原因,那就是減少繼承類的複雜性。一個經典的例子就是iOS UI架構裡面的UITableViewController類。假如沒有“協定”功能,使用者就必須選擇用繼承和重載接口的方法來實作複雜的UI控制以及其他事件的處理——這就對基類的設計提出了更大的挑戰了。對于像這樣一個table view,一個很好的實作方法就是采用協定,由協定裡的接口來控制不同的資料源以及各種複雜的使用者操作。UIKit中設計了兩個很好的協定UITableViewDelegate,UITableViewDataSource來實作UITableViewController的控制。任何遵循這兩個協定的類都可以實作對UITableView的控制。

關于 id類型的運用:(不喜歡鑽牛角尖的朋友,可以略過這一部分)

id 類型在iOS中是一個通用類型,有點類似C語言的void*類型。編譯器不能檢查到定義為id類型的變量的實際類型,id類型的識别是發生在運作時階段。但是我們可以用 id<protocol_name> obj;這樣的文法形式在編譯階段就可以讓編譯器知道obj隻可以發送protocol_name中的消息,如果所發送的消息不在protocol_name中,編譯器會給一個警告資訊“Instance method 'xxxx:' not found......”。這種情況多用于代理模式的實作,比如某一個類有一個delegate 的property:

id <myProtocol> delegate;  

這樣,在編譯階段我們就可以知道用delegate所發送的消息是不是在它所遵循的myProtocol中的消息。好了, 到這裡筆者鑽起了牛角尖,我把id後面的 <myProtocol>删掉,然後用delegate發送一個并不存在于myProtocol中的消息,結果編譯器還是給了“Instance method 'xxxx:' not found......”的警告資訊。更奇怪的是,當發送一個存在于myProtocol中的消息時,編譯器竟然沒有這樣的警告資訊。這兩個測試并不能說明之前的解釋是錯誤的,姑且認為id<myProtocol> delegate這種寫法是為了便于知道這個delegate遵循了myProtocol的協定吧。

如何聯系我:【萬裡虎】www.bravetiger.cn

【QQ】3396726884 (咨詢問題100元起,幫助解決問題500元起)

【部落格】http://www.cnblogs.com/kenshinobiy/