IOS系列——delegate和protocol

原文轉載於 http://haoxiang.org/2011/08/ios-delegate-and-protocol/

今天上班和同事討論工程怎麼組織的時候涉及到這個話題。
iOS開發上對delegate使用廣泛。
記在這裏,如果有新人Google到了,希望能有點幫助。

protocol和delegate完全不是一回事,放在一起說,只是因爲我們經常在同一個頭文件裏看到這兩個word。

protocol和java裏interface的概念類似,是Objective-C語法的一部分。
定義protocol如下

@protocol ClassADelegate
 
- (void)methodA;
- (void)methodB;
 
@end

那麼就是定義了一組函數,這組函數放在一起叫作一個protocol,也就是協議。

函數是需要被實現的,所以如果對於class如下

@interface ClassB <ClassADelegate> {
}
@end

就叫作ClassB conform to protocol ClassADelegate,也就是說ClassB實現了這個協議,
也就是實現了這一組函數。

有了上面這個頭文件,我們就可以放心作調用

ClassB *b = [[ClassB alloc] init];
[b methodA];
[b methodB];

而不用擔心出現unrecognized selector sent to instance這種錯誤了。

所以protocol就是一組函數定義,是從類聲明中剝離出來的一組定義。

id<ClassADelegate> b = ...;
[b methodA];

這種用法也常見,b是一個id類型,它知道ClassADelegate這組函數的實現。

那麼delegate是什麼?其實和protocol沒有關係。Delegate本身應該稱爲一種設計模式。
是把一個類自己需要做的一部分事情,讓另一個類(也可以就是自己本身)來完成。
比如ClassC

@interface ClassC {
    id delegate;
}
@end

那麼ClassC的實現(.m文件)裏就可以用delegate這個變量了。
當然這裏完全可以用其它名字而不是delegate。

我們也可以這樣寫

@interface ClassC {
    ClassB *delegate;
}
@end

這樣我們知道了delegate是一個ClassB,它就可以提供ClassB裏的方法。
可以把一部分ClassC裏的工作放在ClassB裏去實現。
這樣的寫法看起來是不是有點奇怪?或者應該寫成這樣?
@interface ClassC {
    ClassB *classB;
}
@end

…..

delegate沒有了…
所以說其實delegate只是一種模式,大家約定俗成,當把自己內部一部分實現暴露給另外一個類去做的時候,就叫實際做事的類爲delegate。

爲什麼會需要把內部實現提出來給另一個類做呢?
最常見的目的就是爲了在隱藏實現的前提下,提供一個自定義的機會。
比如Apple提供的iOS SDK裏就有衆多的delegate,比如最常用的UITableView,
我們沒法知道Apple怎麼重用UITableViewCell,怎麼處理UITableView裏Cell的增加、刪減,因爲我們沒有源碼。
但是我們可以通過實現Delegate的方法來控制一個UITableView的一些行爲。
UITableViewDataSource其實和delegate是一樣一樣的,只是由於意義不同換了個名字罷了。

protocol在此扮演了什麼角色呢?
protocol是一種語法,它提供了一個很方便的、實現delegate模式的機會。
比如寫UITableView的時候,Apple這麼幹
UITableView.m

- (void)doSomething {
    [self blahblah];
 
    [self.delegate guruguru];
 
    [self blahblah];
 }

delegate是我們寫的類,這個類如果可以被傳給UITableView做爲其delegate,那唯一要求,就是它實現了
- (void)guruguru;

這個方法。

如果我們把這個方法定義在一個protocol裏

@protocol XXXProtocol
- (void)guruguru;
@end
就說明了,UITableView需要的delegate是一個conform to XXXProtocol的類。
這就正好是
id<XXXProtocol>

表達的意思。
無論具體的類是什麼,它還有其它什麼方法,只要它conform to這個protocol,
就說明它可以被傳給UITableView,作爲它的delegate。
那麼Apple爲了讓我們知道這個protocol是delegate需要conform的protocol,
它就把XXXProtocol改成了UITableViewDelegate

這樣我們看到protocol的名字裏有Delegate,就知道這個protocol裏的函數是用來做自定義(Customization)的了。

代碼最終還是給人看的,公司裏尤其如此。
大家都希望對方把事情講得清晰易懂,如果在再有兩句俗語或者行話那大家就很開心了 :]



發佈了59 篇原創文章 · 獲贊 3 · 訪問量 12萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章