本文的原地址是:NotificiationCenter。我对原文做了一些修改,删除了一些冗杂的部分。
A notification dispatch mechanism that enables the broadcast of information to registered observers
Source - Apple Documents
通知分发机制使得信息可以广播给所有注册的观测者。
1 在开始之前我们来看看为什么我们需要这个机制
在移动应用开发中有时候我们需要实现一些诸如处理手机旋转,从一个类向另一个类传递数据,调用任意一个其他函数等等这些问题。一般来说代理模式比较适合两个类之间的通信问题,但是代理模式 (Delegation pattern) 无法实现消息的广播。
代理模式的另一个问题是强耦合性。即我们在消息源中要显式地定义代理。还有一个问题是代理模式需要明确的传递路径,那么在复杂的对象结构中,我们需要传递消息的话可能需要经过冗长的调用过程。
2 如何使用
2.1 接收端
1 | NotificationCenter.default |
上面是一个典型的观测者注册过程。消息传递的中枢是 NotificationCenter
。消息的辨识符是 NSnotification
对象,这个对象的名称应该是唯一的。由于你是用的第三方库中也可能也使用了 NotificationCenter
,如果你选择的名字比较简单(例如在这里只写 'login.success'
),那么有可能和第三方库冲突。因此一般会选择一个类似 bundle ID 的前缀。addObserver
的最后一个参数 。object
是传递给消息的接受函数的对象,即这里的 loginSuccess
函数的输入参数
这里的
object
起到一个筛选作用,用来指明消息的发送者。当不为 nil 时,Observer 只会接受来自这个对象的消息。
2.2 发送消息
将消息发送给所有的观测者方法是
1 | NotificationCenter.default |
这里的
object
参数用来设定消息的发送者,同addObserver
函数中的object
参数配合完成对消息发送源的筛选处理。
3 完整的流程
3.1 Step 1: 实现消息处理函数
1 | @objc |
3.2 Step 2: 注册观测者
1 | NotificationCenter.default |
3.3 Step 3: 发布消息
1 | let loginResponse = ["userInfo": ["userID": 6, "userName": "John"]] |
注意这里使用了 userInfo
来传递数据。
3.4 处理消息发送端传递来的数据
1 | @objc func loginSuccess(_ notification: Notification) { |
3.5 移除消息监听
1 | deinit { |
deinit
用来在一个对象被 deallocated 之后执行一些清理操作。在这里来说,是确保对象析构的时候,移除对应的监听者,避免NotificationCenter对于监听者对象的持有导致对象无法被正确析构。不过在 iOS 9 以后,系统会自动完成对于 Observer 的清理,无需再像这样进行手动清理。对应的文档:removeObserver(_:)
在实际使用中我们要避免在代码中直接写 'com.user.login.success'
这种固定的字符串,偶然的拼写错误可能导致难以理解的 bug。另外,如果我们要修改消息的命名,工作量也会相对较大。因此最好的方法是使用 Swift 的扩展机制
1 | extension Notification.Name { |