NotificationCenter 是 iOS/macOS 开发中的发布-订阅模式(Publish-Subscribe)的通知机制,用于在应用内的不同部分之间传递消息。
NotificationCenter作用
让不同的对象进行通信,而不需要直接引用对方(解耦)。
一个对象发送通知,多个对象可以接收并作出反应。
适用于监听系统级别或自定义的事件(如键盘弹起、iCloud 数据变化等)。
NotificationCenter 的核心概念
1、Notification
通知(Notification)就是一条消息,比如:
“iCloud 数据发生变化了”
“用户登录成功了”
“键盘弹出来了”
“App 进入后台”
2、Observer(监听者)
监听者(Observer)可以监听特定的通知,当通知发布时,监听者会执行相应的方法。
3、Post(发送通知)
发布者(Post)可以向 NotificationCenter 发送通知,通知会被所有监听它的对象接收。
NotificationCenter常用形式
1、添加观察者(监听通知)
Block 形式(更现代、类型安全)
NotificationCenter.default.addObserver(
forName: NSNotification.Name?,
object: Any?,
queue: OperationQueue?,
using: @escaping (Notification) -> Void
)
参数解释:
1、forName:类型Notification.Name?,要监听的通知名,比如 .NSManagedObjectContextDidSave。
2、object:类型Any?,限制通知来源对象(发通知的对象)。设为 nil 表示监听所有来源。
3、queue:类型OperationQueue?,指定处理通知的 block 运行在哪个队列上:nil = 发通知所在的线程.main = 主线程。
4、using:类型(Notification) -> Void,通知到来时要执行的代码。
代码示例:
NotificationCenter.default.addObserver(
forName: .NSManagedObjectContextDidSave,
object: nil,
queue: .main
) { notification in
// 在主线程中处理 Core Data 更新
viewContext.perform {
viewContext.mergeChanges(fromContextDidSave: notification)
}
}
特点:
1、没有 selector,不需要在类里写方法。
2、使用 Swift 闭包,线程控制灵活、安全。
3、易于移除:需要保存返回的 NSObjectProtocol 实例再调用 removeObserver.
传统 Selector 形式(OC风格)
NotificationCenter.default.addObserver(
_ observer: Any,
selector: Selector,
name: NSNotification.Name?,
object: Any?
)
参数解释:
1、observer:类型Any,谁来响应通知(通常是 self)。
2、selector:类型Selector,收到通知后执行的方法名。
3、name:类型Notification.Name?,通知名。
4、object:类型Any?,通知的来源。
代码示例:
NotificationCenter.default.addObserver(
self,
selector: #selector(handleNotification(_:)),
name: NSUbiquitousKeyValueStore.didChangeExternallyNotification,
object: NSUbiquitousKeyValueStore.default
)
@objc func handleNotification(_ notification: Notification) {
// 处理逻辑
}
特点:
1、需要写带 @objc 的方法(兼容 Objective-C)。
2、无法指定在哪个线程执行,和通知发出者线程保持一致。
3、通常用于需要在 NSObject 子类中响应系统通知,如 AppDelegate、UIViewController 等。
2、发送通知
NotificationCenter.default.post(…) 用于主动发送通知消息,它有几种不同的用法,适合在 App 内部不同模块之间传递信息,比如数据更新、用户登录状态变化、任务完成等。
NotificationCenter.default.post(
name: .someNotificationName,
object: self, // 发送者
userInfo: ["key": "value"] // 附加数据
)
name:通知名称(建议用扩展定义 Notification.Name)
object:可选。通知来源,一般为 self,或用于过滤接收来源。
userInfo 是 [AnyHashable: Any]? 类型的字典,用于传递更多上下文信息。
监听方通过 notification.userInfo 读取这些数据。
1、通知名扩展定义(推荐写法)
extension Notification.Name {
static let userDidLogin = Notification.Name("userDidLogin")
}
2、发送通知
NotificationCenter.default.post(
name: .userDidLogin,
object: nil,
userInfo: ["userId": "1234", "name": "Alice"]
)
3、接收通知(Swift block 写法)
NotificationCenter.default.addObserver(
forName: .userDidLogin,
object: nil,
queue: .main
) { notification in
if let info = notification.userInfo as? [String: Any],
let name = info["name"] as? String {
print("欢迎 \(name)")
}
}
还可以设置 object 过滤通知来源:
NotificationCenter.default.addObserver(
forName: .myNotificationName,
object: myManager, // 只监听 myManager 发出的通知
queue: .main
) { ... }
3、移除观察者
Block形式移除监听的方式:
let token = NotificationCenter.default.addObserver(...)
NotificationCenter.default.removeObserver(token)
需要保存 token: NSObjectProtocol 变量。
传统 Selector 形式移除监听:
NotificationCenter.default.removeObserver(self, name: ..., object: ...)
在 Swift 项目中建议尽量使用 Block 形式,特别是 ViewModel、异步数据处理等地方。
只有在必须响应系统通知且不想写闭包时,才考虑 Selector 形式。
监听iCloud数据变化
1、监听通知(添加 Observer)
在代码中,可以监听(addObserver)特定的通知,比如 iCloud 数据变化:
NotificationCenter.default.addObserver(
self,
selector: #selector(handleNotification(_:)),
name: NSUbiquitousKeyValueStore.didChangeExternallyNotification,
object: NSUbiquitousKeyValueStore.default
)
NotificationCenter.default.addObserver(…) → 监听特定通知。
selector: #selector(handleNotification(_:)) → 当收到通知时,执行 handleNotification(_:) 方法。
name: NSUbiquitousKeyValueStore.didChangeExternallyNotification → 监听 iCloud 数据变化。
object: NSUbiquitousKeyValueStore.default → 监听 iCloud KVS(Key-Value Store) 的变化。
2、处理通知
当 NotificationCenter 收到通知后,会执行 handleNotification(_:) 方法:
@objc private func handleNotification(_ notification: Notification) {
print("收到 iCloud 数据变化通知!")
}
3、发送通知
某些时候,可以主动发送通知:
NotificationCenter.default.post(
name: Notification.Name("MyCustomNotification"),
object: nil
)
这样,所有监听 MyCustomNotification 的对象都会收到通知。
4、移除监听
在 deinit 中移除监听,避免内存泄漏:
deinit {
NotificationCenter.default.removeObserver(self)
}
实际应用
监听iCloud和应用生命周期事件,调用对应的方法。
/// 监听 iCloud 变化,同步到本地
private func observeiCloudChanges() {
NotificationCenter.default.addObserver(
self,
selector: #selector(iCloudDidUpdate),
name: NSUbiquitousKeyValueStore.didChangeExternallyNotification,
object: NSUbiquitousKeyValueStore.default
)
}
/// iCloud 数据变化时,更新本地数据
@objc private func iCloudDidUpdate(notification: Notification) {
loadFromiCloud()
}
/// 监听应用生命周期事件
private func observeAppLifecycle() {
NotificationCenter.default.addObserver(
self,
selector: #selector(appWillResignActive),
name: UIApplication.willResignActiveNotification,
object: nil
)
}
/// 当应用进入后台时,将数据同步到 iCloud
@objc private func appWillResignActive() {
syncToiCloud()
}
当iCloud发生变化时,调用iCloudDidUpdate方法,该方法会执行loadFromiCloud方法(该方法表示将iCloud数据同步到本地,在此处省略)。
当应用生命周期发生变化时,同样会调用appDidEnterBackground,该方法也会调用syncToiCloud方法,将数据同步到iCloud。
在类的构造方法中,调用这两个方法,实现监听:
@Observable
class AppStorageManager {
static let shared = AppStorageManager() // 全局单例
private init() {
// 监听 iCloud 变化,同步到本地
observeiCloudChanges()
// 监听应用进入后台事件
observeAppLifecycle()
}
}
在构造方法中运行对应的NotificationCenter方法,从而实现全局事件的监听。
总结
NotificationCenter 适用于全局事件监听,比如:
1、iCloud 数据变化。
2、用户登录状态变化。
3、App 进入后台或前台。
4、设备旋转、键盘弹起等系统事件。
可以把它理解成广播机制,多个对象可以订阅同一个事件,当事件发生时,所有订阅者都会收到通知。