注意事項

在上面的範例中,我們看到了設計 delegate 與 protocol 應該注意的地方:

Delegate 物件不應該指定 Class

我們將 delegate 物件宣告成 id <MyButtonDelegate> delegate,意思就是不需要管這個物件屬於哪個 class,只要是個 Objective-C物件即可,但是這個物件必須實作 MyButtonDelegate protocol。

我們其實可以將 delegate 物件是那個 class 寫死,例如把 MyButton 的 delegate 的 class 指定成MyController,但這樣做非常不好,如此一來,就只有 MyController可以使用 MyButton,其他 controller 都無法使用,就大大減少了重複使用MyButton 的彈性。

Delegate 這種設計方式,也方便我們在同時開發 Mac OS X 與 iOS跨平台專案時共用程式碼,我們在撰寫某個 model 物件的時候,只使用Foundation 或是其他兩個平台都有的framework,至於與平台相依的部份,就放進 delegate 中,然後在 Mac OS X 與iOS 上各自實作 delegate 物件。

總之, 在實作 delegate 的時候,delegate 屬於哪個 class並不重要,重要的是 delegate 物件有沒有實作我們想要呼叫的 method。

Delegate 屬性應該要用 Weak,而非 Strong

在使用 property 語法的時候,如果這個 property 是 Objective-C物件,我們照理說應該要設定成 strong 或 retain,但是遇到的是 delegate,我們應該設成 weak 或 assign。

原因是:需要設計 delegate 物件的這個物件,往往是其 delegate物件的成員變數。在我們的例子中,MyButton 的 instance 是 myButton,是 MyController 的成員變數,自己可能已經被 MyController retain了一份。如果 MyButton 又 retain了一次 MyController,就會出現循環 retain 的問題—我已經被別人 retain,我又把別人 retain 一次。

如此,會造成我們會無法釋放 MyController:在該釋放 MyController的時候,MyController 還是被自己的成員變數 retain,MyController得要走到 dealloc 才會釋放 myButton,但是自己卻因為被 myButton 給retain 起來,而始終走不到 dealloc

Delegate Method 的命名方式

Delegate method 的命名有個鮮明的特色,就是這個 method至少會傳入一個參數,就是把到底是誰呼叫了這個 delegate method傳遞進來。同時,這個 method 也往往以傳入的 class名稱開頭,讓我們可以辨識這是屬於哪個 class 的 delegate method。以UITableViewDelegate 為例,假如我們在 iOS的表格中,選擇了某一列,就會呼叫

- (void)tableView:(UITableView *)tableView
        didSelectRowAtIndexPath:(NSIndexPath *)indexPath

Method 的名稱就以「tableView」開頭,讓我們知道這是屬於 Table View 的 delegate method,然後第一個參數把這個 Table View 的 instance傳入,接下來才傳入到底是哪一列被選起來的資訊。

至少把是誰呼叫了這個 delegate method 傳入的理由很簡單。以我們的 MyController 為例,這個 controller 可能有好幾個 MyButton,而這些 MyButton 全都把 delegate 指到同一個 controller 上,那麼,controller 就需要知道到底是被哪個 button 呼叫。判斷方式只要簡單比對指標就好了:

- (void)myButtonDidBecomeQuadrupleClicked:(MyButton *)button
{
    if (button == myButton1) {
    }
    else if (button == myButton2) {
    }
}

results matching ""

    No results matching ""