軟體設計

Swift Delegate 與 Observer 何時該用哪個?完整比較

進行 iOS 開發時,經常會反覆遇到 Delegate 模式。

閱讀 4 分鐘
Swift Delegate 與 Observer 何時該用哪個?完整比較 封面圖

進行 iOS 開發時,經常會反覆遇到 Delegate 模式。

每次使用 UITableView、UITextField 都要加上 delegate,想必你曾想過:「為什麼是 Delegate?不能直接用閉包或通知嗎?」

尤其學到 Observer 模式後,反而更容易混淆。兩者都是「發生事情時通知」的結構,到底差在哪裡?

先說結論。

Delegate 是一個物件將工作委派給唯一一個對象的 1:1 通訊:「這件事交給你。」

Observer 則是多個訂閱者同時訂閱一個事件的 1:N 廣播。

掌握這一句,就已經理解一半了。今天會搭配程式碼把差異說清楚。


什麼是 Delegate 模式?

Delegate 的意思就是「委派」。

把自己不方便處理的工作交給一個可信任的物件:「請你代替我決定。」

用日常生活來比喻如下。

我想預訂餐廳,但懶得親自打電話,所以請一位秘書:「請幫我預訂。」

這位秘書就是 Delegate。委託者一人,受託者也一人,正好是 1:1。

在 Swift 中,會透過協定約定這件事。

// 以協定定義要委派的工作
protocol OrderDelegate: AnyObject {
    func didFinishOrder(_ menu: String)
}

class Restaurant {
    weak var delegate: OrderDelegate?  // 只指定一個對象
    func order(_ menu: String) {
        delegate?.didFinishOrder(menu)  // 只通知那一個對象
    }
}

值得注意的是,delegate不是陣列,而是單一的屬性

既然只交給一個人,當然只會放一個。這就是 Delegate 為 1:1 的原因。

而且還有weak。彼此強參考會形成 retain cycle 並造成記憶體洩漏,因此 Delegate 通常會以 weak 參考持有。


和 Observer 模式有什麼不同?

Observer 就是「觀察者」。

事件發生時,通知會同時送給正在觀察它的多個對象

繼續用剛才的秘書比喻。

這次我把餐廳開幕消息廣播給整個社區:「今天晚上開幕!」

收聽者可能有十人,也可能有一百人。我不在意誰在聽,只負責廣播出去。

這就是 1:N 廣播,也就是 Observer 模式。

在 iOS 中,NotificationCenter就是代表性的例子。

// 事件發生 → 廣播給所有訂閱者
NotificationCenter.default.post(name: .storeOpen, object: nil)

// 有興趣的物件各自訂閱
NotificationCenter.default.addObserver(
    self, selector: #selector(handleOpen),
    name: .storeOpen, object: nil)

傳送方不知道接收者是誰,只會加上名稱後送出去。

接收方也由多個物件各自訂閱。

彼此不必知道對方,因此耦合度較低;但缺點是難以追蹤目前誰正在接收通知。

親自寫過程式碼後,才終於抓到感覺
親自寫過程式碼後,才終於抓到感覺

Delegate 與 Observer 一眼比較

只用文字說明容易混淆,所以整理成表格。

1:1 委派與 1:N 廣播,用圖看就很清楚
1:1 委派與 1:N 廣播,用圖看就很清楚
分類 Delegate Observer
通訊方式 1:1(委派給一人) 1:N(廣播給多人)
是否知道對方 彼此清楚知道 彼此不必知道
代表範例 UITableViewDelegate NotificationCenter
回應(回傳值) 容易接收 較難接收
耦合度 相對較高
追蹤/除錯 容易 較困難

關鍵在於「是否需要取得回應」。

Delegate 會在你問「這個儲存格要多高?」時回傳數值,是雙向對話的結構。

Observer 只負責送出通知。傳送方不在意誰會如何回應。


那麼什麼時候該用哪個?

這是我實際在專案中使用後整理出的判斷基準。

使用 Delegate 的時機

  1. 只需要與一個物件溝通時
  2. 需要從對方取得數值時(例如儲存格數量、高度)
  3. 畫面轉換等順序與流程明確時

使用 Observer 的時機

  1. 一個事件需要多個畫面同時反應時
  2. 登入狀態變更、切換深色模式等全域事件
  3. 傳送方與接收方不必知道彼此時

例如登入成功後,首頁、我的頁面與頂端橫幅都要同時更新時,用 Delegate 就很吃力。

因為只能委派給一人,若要連接三個地方,程式碼會變得凌亂。

這時用 Observer 廣播一次「登入成功了!」會乾淨得多。

相反地,「按下輸入欄位的確認按鈕」這種 1:1 情境,Delegate 或閉包才是正解。

在白板上用箭頭畫出來,就會容易許多
在白板上用箭頭畫出來,就會容易許多

總結

即使兩者看起來相似,只要想想「要通知幾個人」,就很容易選擇。

一人用 Delegate,多人用 Observer。記住這個基準就夠了。

下次寫程式時試著套用今天學到的內容吧。當只停留在腦中的知識真正融入手感,模式就會變得容易許多。為你加油!

延伸閱讀