软件设计

Swift 观察者模式:从 NotificationCenter 到 Combine

开发 iOS 应用时,你一定会遇到这种情况:A 页面发生了变化,而距离很远的 B 页面也需要同步更新。

3 分钟阅读
Swift 观察者模式:从 NotificationCenter 到 Combine 封面图

开发 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 的观察者模式。

不要一开始就追求完全理解,先亲手创建一个小通知吧。实际写一遍,就能更快掌握要领。加油!

延伸阅读