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的協議吧。
  本文若有任何錯誤,歡迎拍磚指正,謝謝!
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章