2015年11月18日 星期三

[iOS] kkbox-ios-dev note Delegate與Protocal

在閱讀這一章之前,相信你應該已經寫過一些簡單的iOS程式,
知道如果我們想要一個像是系統設定(Setting.app)那樣的表格介面,
我們會建立UITableViewController的subclass,這個controller的view是
UITableView。

當我們想要設定表格中的內容,像是這個表格中有多少個section,
每個section裡有多少row、每個row裡面又是那些內容...我們不是直接呼叫
UITableView的method,像是呼叫[myTableView setSectionCount:3]或是
[myTableView setRowCount:3 atSection:4],而是去實作UITableViewController
裡面幾個像是template method的東西,像numberOfSectionsInTableView:、
tableView:numberOfRowsInSection:等等。

為什麼不是直接去改變view而是controller要準備一些不知道會被誰呼叫的method?
理由是:UITableViewController是UITableview的data source與delegate。
那什麼是delegate?

用我的話來說delegate就是將眾多的callback,集中在一個物件上。

從其他平台來看Objective-C的Delegate
Delegate算是入門Objective-C的另外一個障礙,但了解之後就會知道其實非常簡單,
一開始可能覺得並不好懂的主要原因是,delegate的這套作法,跟其他平台在做同樣的事情的時候,作法比較不一樣。

如果你曾經在其他的平台上開發過應用程式,像是微軟的.Net平台的話,可以發現,在C#語言中在講一個class有那些成員的時候,會包括properties、methods以及events;但是我們在講Objective-C的class時,並不會提到events,C#中使用events在做的事情,在Objective-C中,我們往往使用target/action與delegate實作。

雖然在Mac OX X與iOS分別有NSEvent與UIEvent,但是這邊的events與.Net裡面講的events又是兩件事情:NSevent是用來描述鍵盤按了那個按鍵,滑鼠移到了什麼位置,而UIEvent是用來描述觸控事件以及耳機上的播放控制按鈕等等,單純用來描述從硬體輸入了什麼事件,透過作業系統傳到我們的應用程式中。而C#裡面所稱的events,則是用來處理callback。

所謂callback是指,當我們呼叫了一個function或method之後,可能會花上許多時間,或是計算的是大量資料,或是需要透過網路連線,所以我們並不馬上要求得到回傳的結果,而是等到一段時間之後,計算結果才會透過另外一個function/method傳回來。

現在絕大多數的應用程式開發環境都採用MVC架構,我們將物件分成三類:model、view、controller,雖然在不同的平台上往往實作出來的結果不太一樣,像是在微軟的平台上,往往把window(或是frame)當作是controller由window物件責管理放在這個window上面所有的control元件,但是Mac OS X上面window並不拿來當做controller,而是被當成view,controller在window之外,而且一個controller也可以控制多個winodw...但都大抵如此。

在MVC的架構中,我們通常會先建好controller class,然後加入model與view,變成controller的成員變數;因為model與view是controller的成員變數,所以controller可以直接呼叫model與view,那麼,當model與view發生了變化,要回來通知controller,我們也可以稱之為callback,例如,controller建立了一個按鈕,但是直到按鈕被點選之後,controller才負責做事。

在C#中我們要處理一個event,就要提供一個event handler,我們現在要處理的是Click:
private void InitializeComponent() {
 this.button1 = new System.Windows.Forms.Button();
 this.button1.Click += Button1_Click;
}

private void Button1_Click(object sender, System.EventArgs e) {
}
如果只是單純的點選事件的話,我們會用target/action實作。但,對照.Net framework裡頭,events不只是click而已,還可能會有double click,triple click,quadruple click...,只果是C#裡頭,會這麼寫:

this.button1.Click += Button1_Click;
this.button1.DoubleClick += Button1_DoubleClick;

變成Objective-C的話就可能變成
 [button1 setTarget:self];
[button1 setAction:@selector(click:)];
[button1 setDoubleTarget:self];
[button1 setDoubleAction:@selector(doubleClick:)];
這樣寫起來實在很讓人煩躁(雖然NSTableView也的確有setDoubleAction:...) 所以當這樣的東西一多,在Objective-C語言裡頭,會直接準備好一個物件,這個物件準備好了 所有可以呼叫的method,這個物件就叫做delegate,而這些可以呼叫method的集合,叫做protocol。 好這個物件之後,我們就不用呼叫那麼多setDoubleAction,只要呼叫setDelegate。

沒有留言:

張貼留言