开发 iOS 应用时,你一定会遇到这种情况: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 的观察者模式。
不要一开始就追求完全理解,先亲手创建一个小通知吧。实际写一遍,就能更快掌握要领。加油!

