11、無事勿擾,有事通知(2)——KVO

概述html

Key-Value-Observe,簡稱KVO,和上節介紹的Notification師出同門,主要目的都是爲了實現觀察者模式。swift

雖然說是同門師兄弟,可是各自精通的技藝倒是各不相同的。併發

不像Notification,KVO沒有所謂「Center」的角色,觀察者和被觀察者之間是直接交互的,沒有第三者插腳。這個特色帶來的最直接的好處就是,KVO比Notification更加的簡單易用。陰陽相隨,利弊相從。正由於KVO沒有「Center」約束,因此當參與觀察和被觀察的角色增多的時候,KVO管理起來就會顯得力不從心了,並且當有大量事件併發執行的時候,NotificationCenter還有整合優化以提升性能的做用,而KVO則沒有這方面的內容(出處)。ide

最後須要注意的一點是,KVO是相伴NSObject的產物,NSObject是Object-C的基類,在swift中,並不是全部的類都繼承了NSObject,這也就意味着並不是全部的類都能用KVO。然而,這些倒並不構成咱們使用KVO的顧慮,畢竟大部分經常使用的類都是繼承NSOject的,咱們大可放心使用KVO,尤爲在觀察對象單個屬性變化方面,KVO絕對是個不可多得的好幫手。函數

 

單點,碼代碼的方式簡單點性能

在上一節Notification中,咱們又是要建立NotificationCenter又是要重寫UILabel,實在是太麻煩了,這節我們簡單點,實現一個和上一節同樣的程序。優化

 1 import UIKit
 2 
 3 class ViewController: UIViewController {
 4     @IBOutlet weak var passby1: UILabel!
 5     @IBOutlet weak var passby2: UILabel!
 6     @IBOutlet weak var passby3: UILabel!
 7     
 8     @objc dynamic var passerby1Say:String = ""
 9     @objc dynamic var passerby2Say:String = ""
10     @objc dynamic var passerby3Say:String = ""
11 
12     override func viewDidLoad() {
13         super.viewDidLoad()
14         addObserver(self, forKeyPath: #keyPath(passerby1Say), options: [.new], context: nil)
15         addObserver(self, forKeyPath: #keyPath(passerby2Say), options: [.new], context: nil)
16         addObserver(self, forKeyPath: #keyPath(passerby3Say), options: [.new], context: nil)
17     }
18     
19     override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
20         if keyPath == #keyPath(passerby1Say) {
21             passby1.text = change![NSKeyValueChangeKey.newKey] as! String
22         } else if keyPath == #keyPath(passerby2Say) {
23             passby2.text = change![NSKeyValueChangeKey.newKey] as! String
24         } else if keyPath == #keyPath(passerby3Say) {
25             passby3.text = change![NSKeyValueChangeKey.newKey] as! String
26         }
27     }
28 
29     override func didReceiveMemoryWarning() {
30         super.didReceiveMemoryWarning()
31         // Dispose of any resources that can be recreated.
32     }
33     
34     @IBAction func flyHeighAction(_ sender: UIButton) {
35         passerby1Say = "路人甲:我不信"
36         passerby2Say = "路人乙:我會信?"
37         passerby3Say = "路人丙:差點信了"
38     }
39     
40     deinit {
41         removeObserver(self, forKeyPath: #keyPath(passerby1Say))
42         removeObserver(self, forKeyPath: #keyPath(passerby2Say))
43         removeObserver(self, forKeyPath: #keyPath(passerby3Say))
44     }
45 }
View Code

 

這下夠簡單了吧,代碼部分總過不超過五十行,運行結果和上一節是同樣兒同樣兒的(效果圖)。如今咱們來簡單分析一下。spa

首先,咱們肯定UIViewController是繼承自NSObject的,因此咱們能夠調用「addObserver」函數和重寫「observeValue」函數。code

而後咱們把須要觀察的屬性用addObserver歸入觀察範圍。server

addObserver函數的做用是:調用addObserver函數的對象將一個NSObject的屬性歸入觀察範圍。

此處調用addObserver的是ViewController,因此ViewController是觀察者。

addObserver的第1個參數是被觀察者,此處爲self,因此ViewController又是被觀察的對象。

addObserver的第2個參數是被觀察者的屬性,此處爲passerby1Say/passerby2Say/passerby3Say。passerby1Say/passerby2Say/passerby3Say必須由dynamic關鍵字修飾,表示支持動態觀察,@objc是修飾語句「#keyPath」要求的,用於編譯階段檢查錯誤。

addObserver的第3個參數是1個列表,表示觸發觀察事件屬性,「.new」表示所觀察的屬性改變時,將新值做爲參數傳遞給觀察者;「.old」表示所觀察的屬性改變時,將舊值做爲參數傳遞給觀察者。

addObserver的第4個參數表示觀察事件觸發時所傳遞的參數,通常不多用到,此處置爲nil。

 

既然咱們已經將所要關注的屬性都歸入觀察範圍了,那麼如今咱們只要關注觀察事件發生時的情形就能夠了。

觀察者經過「obsserveValue」函數接收觀察事件,其中參數change是1個字典,它包含了屬性改變前的舊值或改變後的新值,依據以前調用addObserver時的參數options而定,其餘代碼是不言自明的,此處再也不贅述。

 

源碼下載:https://pan.baidu.com/s/1TosFFebbSuo6qlKVRuZtxg

 

上一節           回目錄          下一節 

相關文章
相關標籤/搜索