在观察者模式里,一个对象在状态变化的时候会通知另一个对象。参与者并不需要知道其他对象的具体是干什么的 - 这是一种降低耦合度的设计。这个设计模式常用于在某个属性改变的时候通知关注该属性的对象。
常见的使用方法是观察者注册监听,然后再状态改变的时候,所有观察者们都会收到通知。
在 MVC 里,观察者模式意味着需要允许 Model 对象和 View 对象进行交流,而不能有直接的关联。
Cocoa 使用两种方式实现了观察者模式: Notification
和 Key-Value Observing (KVO)
。
通知 - Notification
不要把这里的通知和推送通知或者本地通知搞混了,这里的通知是基于订阅-发布模型的,即一个对象 (发布者) 向其他对象 (订阅者) 发送消息。发布者永远不需要知道订阅者的任何数据。
Apple 对于通知的使用很频繁,比如当键盘弹出或者收起的时候,系统会分别发送 UIKeyboardWillShowNotification/UIKeyboardWillHideNotification
的通知。当你的应用切到后台的时候,又会发送 UIApplicationDidEnterBackgroundNotification
的通知。
如何使用通知
//发布者发布通知
//当需要下载图片时发布下载图片通知
NSNotificationCenter.defaultCenter().postNotificationName("BLDownloadImageNotification", object: self, userInfo: ["imageView":coverImage, "coverUrl" : albumCover])
//订阅者订阅通知
init {
super.init
NSNotificationCenter.defaultCenter().addObserver(self, selector:"downloadImage:", name: "BLDownloadImageNotification", object: nil)
}
//取消监听消息
deinit {
NSNotificationCenter.defaultCenter().removeObserver(self)
}
//下载图片
func downloadImage(notification: NSNotification) {
//下载图片code
}
注意:
- 名称需要一致
- 在实现 downloadImage() 之前,我们必须先在 dealloc 里取消监听。如果没有取消监听消息,消息会发送给一个已经销毁的对象,导致程序崩溃。
键值观察 - KVO
在 KVO 里,对象可以注册监听任何属性的变化,不管它是否持有。
//把 self (也就是当前类) 添加到了 coverImage 的 image 属性的观察者里
coverImage.addObserver(self, forKeyPath: "image", options: nil, context: nil)
//在销毁的时候,我们也需要取消观察。
//注意:一定要记得移除观察者,否则如果对象已经销毁了还给它发送消息会导致应用崩溃。
deinit {
coverImage.removeObserver(self, forKeyPath: "image")
}
//必须在所有的观察者里实现上面的代码。在检测到属性变化的时候,系统会自动调用这个方法。
override func observeValueForKeyPath(keyPath: String, ofObject object: AnyObject, change: [NSObject : AnyObject], context: UnsafeMutablePointer<Void>) {
if keyPath == "image" {
indicator.stopAnimating()
}
}