Objective-C 協議(protocol)

協議(protocol)是Objective-c中一個很是重要的語言特性,從概念上講,很是相似於JAVA中接口. 一個協議其實就是一系列有關聯的方法的集合(爲方便後面敘述,咱們把這個協議命名爲myProtocol)。協議中的方法並非由協議自己去實現,相反而 是由遵循這個協議的其餘類來實現。換句話說,協議myProtocol只是完成對協議函數的聲明而並無論這些協議函數的具體實現。app

聲明一個協議的語法很是簡單:框架

  1. @protocol myProtocol <NSObject>  
  2. @required  
  3. -(void) protocolNameA:(NSString*)string;  
  4. @optional  
  5. -(void) protocolNameB:(NSString*)string;  
  6. @end  

第一行是聲明這個協議的名字爲myProtocol。尖括號中的NSObject自己也是一個協議,其中定義了不少基本的協議函數,好比 performSelector,isKindOfClass,respondsToSelector,conformsToProtocol,retain,release 等。

協議接口分爲required和optional兩類。required顧名思義是說遵照這個協議的那個類「必需要」實現的接口,而optional則是能夠實現也能夠不實現的。協議接口的定義和普通的函數定義是同樣的。函數

最後一行@end表示協議定義結束。這個協議的定義一般是在.h文件中。測試


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

  1. @interface myClass  <myProtocol>  
  2. @interface myClass :NSObject<myProtocol>  
  3. @interface myClass :NSObject<myProtocol, NSCoding>  
上 面分別是三種不一樣的狀況。編譯的時候編譯器會自動檢查myClass是否實現了myProtocol中的必要的(@required)接口。若是沒有實現 則會發出一個警告信息。另外須要注意的是,若是有繼承自myClass的子類,這些子類也是會自動遵循myClass所遵循的協議的,並且也能夠重載這些 接口。


爲何須要協議?spa

蘋果的官方文檔指出三個緣由:.net

  • 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:

     

    1. id <myProtocol> delegate;  

    這樣,在編譯階段咱們就能夠知道用delegate所發送的消息是否是在它所遵循的myProtocol中的消息。好了, 到這裏筆者鑽起了牛角尖,我把id後面的 <myProtocol>刪掉,而後用delegate發送一個並不存在於myProtocol中的消息,結果編譯器仍是給了「Instance method 'xxxx:' not found......」的警告信息。更奇怪的是,當發送一個存在於myProtocol中的消息時,編譯器居然沒有這樣的警告信息。這兩個測試並不能說 明以前的解釋是錯誤的,姑且認爲id<myProtocol> delegate這種寫法是爲了便於知道這個delegate遵循了myProtocol的協議吧。

  •  
  • 本文如有任何錯誤,歡迎拍磚指正,謝謝!
相關文章
相關標籤/搜索