開發 iOS App 時,總會遇到這種情況:A 畫面發生變更,遠處的 B 畫面也必須同步更新。
如果硬是用代理程式把畫面彼此連起來,程式碼很容易像義大利麵一樣糾結。
這時就該使用觀察者模式。先說結論,在 Swift 中從 NotificationCenter 開始,再轉向 Combine,是最自然的流程。
本文會從觀察者模式的概念開始,介紹 NotificationCenter 的用法,以及現今常用的 Combine,並搭配實際程式碼說明。
什麼是觀察者模式?
觀察者模式是一種結構:當某個對象的狀態改變時,會自動通知正在監看的物件。
可以想像 YouTube 訂閱。頻道(發布者)上傳影片後,訂閱者(觀察者)就會收到通知。
重點在於發布者和觀察者不必直接知道彼此的存在。
頻道不在意有多少訂閱者,也不在意他們是誰,只要喊一聲「影片上架了」即可。
這種鬆散耦合能讓程式碼不易糾結,之後修改也方便許多。
NotificationCenter 怎麼使用?
NotificationCenter 是 Apple 內建的觀察者模式工具,不需額外的函式庫就能直接使用。
首先定義通知名稱,接著撰寫發布端的程式碼。
// 定義通知名稱
extension Notification.Name {
static let didLogin = Notification.Name("didLogin")
}
// 登入成功時發布通知
NotificationCenter.default.post(name: .didLogin, object: nil)
接收端則可以這樣註冊觀察者。
// 訂閱通知
NotificationCenter.default.addObserver(
self, selector: #selector(handleLogin),
name: .didLogin, object: nil
)
有一點要注意:舊式方法(addObserver + selector)若在畫面消失時沒有呼叫 removeObserver,可能會產生問題。
不過 iOS 9 以上已有更多部分會自動清理;使用區塊式 API 時,只要留意管理回傳的權杖即可。
改用 Combine 有什麼好處?
Combine 是 Apple 在 2019 年發表的反應式程式設計框架,從 iOS 13 開始即可使用。
NotificationCenter 也能轉換成 Combine 的 Publisher,因此可以自然地和既有程式碼混用。
// NotificationCenter改成 Combine 方式
let token = NotificationCenter.default
.publisher(for: .didLogin)
.sink { _ in
print("偵測登入!")
}
Combine 真正的優點,在於可以將資料流串接起來。
可以使用 map、filter 等運算子加工值,也能合併多個事件。
將 sink 回傳的訂閱(AnyCancellable)存入變數後,變數消失時訂閱也會自動取消,記憶體管理輕鬆許多。
所以該用哪一個?
要看情況。以下用表格整理。
| 項目 | NotificationCenter | Combine |
|---|---|---|
| 導入時機 | 較舊的內建 API | iOS 13+ |
| 學習難度 | 低 | 中等以上 |
| 值加工 | 困難 | 使用 map/filter 彈性處理 |
| 記憶體管理 | 需手動處理 | 保存訂閱後自動處理 |
只有一兩個簡單通知時,NotificationCenter 就足夠了。
相反地,如果資料流複雜,或需要組合多個事件,Combine 會整潔得多。
如果是第一次接觸,先用 NotificationCenter 熟悉概念,習慣後再轉向 Combine。
當然,現在 SwiftUI 和 async/await 正夯,因此新專案也建議一併考慮這兩者。
總結
今天從 NotificationCenter 到 Combine,快速瀏覽了 Swift 的觀察者模式。
不用一開始就追求完全理解,先親手做出一個小通知吧。實際寫過之後,很快就能掌握訣竅。加油!

