標籤:
協議(protocol)是Objective-c中一個非常重要的語言特性,從概念上講,非常類似於JAVA中介面. 一個協議其實就是一系列有關聯的方法的集合(為方便後面敘述,我們把這個協議命名為myProtocol)。協議中的方法並不是由協議本身去實現,相反而是由遵循這個協議的其他類來實現。換句話說,協議myProtocol只是完成對協議函數的聲明而並不管這些協議函數的具體實現。
聲明一個協議的文法非常簡單:
[cpp] view plaincopy
- @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檔案中。
定義一個類遵循這個協議:
[cpp] view plaincopy
- @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:
[cpp] view plaincopy
- id <myProtocol> delegate;
這樣,在編譯階段我們就可以知道用delegate所發送的訊息是不是在它所遵循的myProtocol中的訊息。好了, 到這裡筆者鑽起了牛角尖,我把id後面的 <myProtocol>刪掉,然後用delegate發送一個並不存在於myProtocol中的訊息,結果編譯器還是給了“Instance method ‘xxxx:‘ not found......”的警告資訊。更奇怪的是,當發送一個存在於myProtocol中的訊息時,編譯器竟然沒有這樣的警告資訊。這兩個測試並不能說明之前的解釋是錯誤的,姑且認為id<myProtocol> delegate這種寫法是為了便於知道這個delegate遵循了myProtocol的協議吧。
Objective-C 協議(protocol)