[iOS] delegate and protocal

iOS開發廣泛使用delegate,官方文件也到處充斥著delegate字眼。delegate這概念也困惑我很久,有好幾次試圖想弄明瞭卻都失敗告終,直到最近看到了這篇文章,才終於了解,因此把心得記在這邊,除了讓自己更記得,也希望給其他學習者一點幫助。

首先,我鼓勵各位先讀讀上面那篇文章。

protocal

protocal是Obj-C的一種語法,跟java的interface概念一樣;而delegate則是一種設計方式,就跟MVC一樣,容我在重複一次delegate不是一種語法,是一種設計方式。

Obj-C裡,protocal就是定義一些方法,凡是宣稱自己遵守這個protocal的人,就必須要實作這些方法,不能讓別人要呼叫的時候找不到方法。例如定義protocal如下

@protocal 清潔技能LV1
-(void) 掃地
-(void) 擦桌子
@end

然後有個「菜鳥清潔工」Class宣稱它遵守這個protocal

@interface 菜鳥清潔工<清潔技能LV1>{
}
@end

任何物件宣稱了自己遵守「清潔技能LV1」protocal都必須實作「-(voidi) 掃地」與「-(void) 擦桌子」方法。所以在「菜鳥清潔工.m」檔裡就會看到

-(void) 掃地
{
NSLog(@"拿一隻掃把,然後掃地")
}

以及

-(void) 擦桌子
{
NSLog(@"拿一個抹布,然後擦桌子。")
}

有了這樣的實作之後,就可以放心呼叫函數

菜鳥清潔工 *小明 =[ [ 菜鳥清潔工 alloc] init];
[小明 掃地];
[小明 擦桌子];

另外這也是常見的方式

id<清潔技能LV1> 小明 = …;
[小明 掃地];
[小明 擦桌子];

你絕對不會看到「不存在函數 -(void) 掃地」之類的error messag(s)。所以說protocal就是一種協議,定義了協議對象必須有的method(s)

。凡貼上GAS標章,品質保證
。凡遵守「清潔技能LV1」protocal的Class,其instances必有「掃地」與「擦桌子」的method可調用(invoke)。

接著來談談什麼是delegate。

delegate

delegate中文解釋叫做「委派」,官方的解釋在這裡,只看字面或是官方的解釋,都很難懂。

在我理解後,發現他其實是個很簡單的概念,就是「幫手」的意思:一個Class的某些事情委託給別的Class來完成,被委託的對象,就是delegate(幫手的意思)。

@interface 雜貨店
{
id delegate;
}

這個「雜貨店」Class宣告了幫手,沒有人規定幫手一定得叫delegate,delegate這個字也可以換成任意其他字,譬如叫做工讀生好了。

@interface 雜貨店
{
id 工讀生;
}

而當你需要工讀生掃地的時候,你可能會呼叫

[工讀生 掃地]

但是這個呼叫很可能會失敗,因為沒人保證工讀生有實作「掃地」這個method。但是你如果找一個具有「清潔技能LV1」的人,那叫他去掃地就一定沒問題。

@interface 雜貨店
{

id<清潔技能LV1> 工讀生;
}

有了「清潔技能LV1」這個protocal加持,就代表這位工讀生懂得掃地與擦桌子。另外一種寫法也可以:你知道職場上有一種人,它一定具備「清潔技能LV1」,那你也可以寫成

@interface 雜貨店
{
菜鳥清潔工 *工讀生;
}

所以說,當你需要幫手的時候,這代表你需要別人的某些技能來幫你完成工作,所以常常會看到

在「雜貨店.m」裡,有著這麼一個方法

-(void) 讓地板變乾淨
{
[self.blahblah];
[self.工讀生 掃地];
}

雜貨店把「掃地」這件事情,委派給其他人去做,在這個例子就是工讀生。換句話說,「掃地」這件事情被外包了。

呼叫幫手去掃地,這個呼叫可以成立的唯一條件就是該幫手實現了掃地這method。而規範哪些method必須被實作,這不就是protocal在做的事情嘛?所以delegate常常會和protocal掛勾:某Class要把一些工作(task)外包給其他人,需要調用(invoke)別人的某些技能(method),而protocal就像是證照一樣,證明了這個人擁有必須具備的技能。

而在apple的framework裡面,這些「認證」過的幫手protocal,在命名上通常會在末端加上delegate字樣,以清楚表明它可以作為誰的「幫手」,例如實作UITableViewDelegate的instance就是UITableView的合格幫手。

那為什麼要使用delegate呢?或者換句話問,為什麼要把Class自己內部的工作外包給其他Class做呢?apple的說法是可以只定義一個method就讓許多不同的Class使用,例如雜貨店跟魚店都需要把店面整理乾淨,他們不需要自己去實作打掃的細節,叫「菜鳥清潔工」(的instances)來打掃就可以了。

不過很多說法是,apple把delegate反過來用,apple寫的Class並沒給你source code,因此很多Class內部運作細節你並不知道,所以,透過delegate,他開放一些method讓你可以自定義Class的行為,換句話說,你是以「幫手」的身分去參與整個Class的運作,並從而改變它的行為。

最好的例子大概就是UITableView,UITableView是個複雜的Class,裡面有很多東西像是Cell的增加、刪減這些細節實作,你並不曉得,但是你可以透過實現delegate方法來控制UITableView的一些行為或外觀。

拿此篇的例子來講,當你需要一個乾淨的雜貨店時,派一個叫小明的人去把它打掃乾淨就好,不用真的去care雜貨店補貨、上架、營運…等細節

@interface 小明 : 人
{
雜貨店 *店面A;
}

小明.m裡:

-(void) 應徵工作
{
[店面A.工讀生 self];
}

[object.delegate self]; 有沒有似曾相識?

廣告

發表迴響

在下方填入你的資料或按右方圖示以社群網站登入:

WordPress.com Logo

您的留言將使用 WordPress.com 帳號。 登出 / 變更 )

Twitter picture

您的留言將使用 Twitter 帳號。 登出 / 變更 )

Facebook照片

您的留言將使用 Facebook 帳號。 登出 / 變更 )

Google+ photo

您的留言將使用 Google+ 帳號。 登出 / 變更 )

連結到 %s