定義
協(xié)議是多個(gè)類(lèi)共享的一個(gè)方法列表。協(xié)議中列出的方法沒(méi)有對(duì)應(yīng)的實(shí)現(xiàn),計(jì)劃由他人來(lái)實(shí)現(xiàn)。協(xié)議提供了一種方式,用指定的名稱(chēng)定義一組相關(guān)的方法。這些方法通常由文檔說(shuō)明,所以實(shí)現(xiàn)者知道知道它們將如何執(zhí)行。
定義一個(gè)協(xié)議的方法很簡(jiǎn)單,只需要使用@protocol指令,后面跟上你給處的協(xié)議名稱(chēng)。然后,和處理@interface一樣,聲明一些方法。@end指令之前的所有方法聲明都是協(xié)議的一部分。
如果選擇使用Foundation框架,你將會(huì)發(fā)現(xiàn)一些已定義的協(xié)議。其中一個(gè)名為NSCopying,而且它聲明了一個(gè)方法。下面是標(biāo)準(zhǔn)Foundation頭文件NSOBject.h中定義NScopying協(xié)議的方式:NSObject.h:
@protocol NSCopying
- (id)copyWithZone:(NSZone *)zone;
@end
使用
如果你的類(lèi)使用NSCopying協(xié)議,則必須實(shí)現(xiàn)copyWithZone:方法。通過(guò)在@interface行加一對(duì)尖括號(hào)(<……>)內(nèi)列出協(xié)議名稱(chēng),可以告知編譯器你正在采用一個(gè)協(xié)議,如:
@interface AddressBook : NSObject <NSCopying>
其含義為,AddressBook是父類(lèi)為NSObject的對(duì)象,并且它遵守NSCopying協(xié)議。因?yàn)橄到y(tǒng)已經(jīng)知道以前為這個(gè)協(xié)議定義的方法(從頭文件NSObject.h中獲知),所以并不必在接口部分聲明這些方法。但是要在實(shí)現(xiàn)部分定義它們。編譯器期望在AddressBook的實(shí)現(xiàn)部分找到定義的copyWithZone:方法。
如果你定義了自己的協(xié)議,不必由自己去實(shí)現(xiàn)它。但是,這就告訴其他程序員,如果要采用這項(xiàng)協(xié)議,則必須實(shí)現(xiàn)這些方法。這些方法可以從父類(lèi)繼承。這樣,如果一個(gè)類(lèi)遵守NSCopying協(xié)議,那么它的子類(lèi)也遵守NSCopying協(xié)議(不過(guò)者并不意味著對(duì)該子類(lèi)而言,這些方法得到了正確的實(shí)現(xiàn))。
注意事項(xiàng)
- 協(xié)議不引用任何類(lèi)!它是無(wú)類(lèi)的(classless)。任何類(lèi)都可以都可以遵守某個(gè)協(xié)議 ;
- 分類(lèi)也可以采用一項(xiàng)協(xié)議;
- 協(xié)議也可以采用一項(xiàng)協(xié)議;
- 和類(lèi)名稱(chēng)一樣,協(xié)議名必須是唯一的。
代理 Delegate
協(xié)議也是一種兩個(gè)類(lèi)之間的接口定義。定義了協(xié)議的類(lèi)可以看做是將協(xié)議定義的方法代理給了實(shí)現(xiàn)它們的類(lèi)。這樣,類(lèi)可以更為通用,因?yàn)榫唧w的動(dòng)作由代理來(lái)承擔(dān),來(lái)響應(yīng)某些事件或者定義某些參數(shù)。Cocoa和iOS非常依賴(lài)這個(gè)概念。例如,當(dāng)你在iPhone上建立一個(gè)表格時(shí),會(huì)使用UITableView類(lèi)。但是這個(gè)類(lèi)不清楚表格的標(biāo)題是什么,需要包含多少個(gè)區(qū)塊有多少行,填充單元格的內(nèi)容是什么。所以,代理定義了一個(gè)UITableViewDataSource協(xié)議。如果它需要信息,比如表格中的每個(gè)區(qū)塊有多少行,它就會(huì)調(diào)用類(lèi)中實(shí)現(xiàn)協(xié)議的相關(guān)方法。UITableView類(lèi)還定義了協(xié)議UITableViewDelegate。協(xié)議中還定義了一些方法,如表格中某些行選中需要怎么樣。UITableView類(lèi)并不知道還要做哪些事情,所以將這個(gè)代理給其他類(lèi)。
歡迎來(lái)我的個(gè)站逛逛: http://alexyu.me/