iOS里的KVO

背景

最近遇到了一個需求,一個頁面上好幾個按鈕都依賴于某一個model的變化而做相應(yīng)的變化,每次在model變化的時候分別對各個按鈕做更新倒是也可以,就是有點麻煩,于是我想到了KVO,當(dāng)model變化的時候。自動通知需要知道的按鈕,讓按鈕自身去做這件事。然而,事情并不那么簡單。

基礎(chǔ)

keyPath

首先了解下keyPath,因為可能很多同學(xué)都卡在這里了。在 Swift 中,keyPath是用來表達(dá)訪問屬性時的關(guān)鍵路徑。什么是路徑呢?假設(shè)我們有一個Person類和一個Person類的實例,例如:

class Person {
    var sex = 0
}
let someone = Person()

我們訪問實例的屬性時會用someone.sex 的語句, 這里的someone.sex 就是表達(dá)式訪問人物類的性別屬性的路徑。
那么keyPath怎么表達(dá)這個路徑呢,有三種方式:

  1. 使用鍵路徑表達(dá)式 \Person.sex
    這種方式里,我們希望訪問someone這個實例的sex屬性。應(yīng)該先語法,然后寫實例的類和.運算符,最后寫我們希望觀察的屬性。
  2. 使用 #keyPath(Person.sex))
    這里的#keyPath 表達(dá)式的語法很像選擇器表達(dá)式(#selector)的語法,其中使用這種方法獲取對象的屬性值時,屬性要 @objc 修飾,否則會報錯。
  3. 字符串
    字符串的方式可以直接寫要觀察的屬性路徑,不需要寫根類型,例如觀察sex屬性的話可以直接寫"sex"

KVO的前提

  1. KVO是NSObject才有的功能,也就是說,如果像我們上邊寫的Person類,它沒有繼承NSObject的話,是不支持KVO的。
  2. KVO的屬性需要是@objc, 'dynamic' 修飾的, 如果是像我們上邊提到的sex屬性,在編譯的時候就會提示我們?nèi)缦洛e誤
Cannot convert value of type 'ReferenceWritableKeyPath<Person, Int>' to expected argument type 'String'

實踐

假設(shè)我們有一個對象想要觀察Person實例的sex屬性的話。應(yīng)該怎么操作呢

  1. 首先我們?yōu)閷嵗砑右粋€觀察者
let someone = Person()
someone.sex = 0
someone.addObserver(self, forKeyPath: \Person.sex, options: [.new], context: nil)
  1. 然后我們重寫observe函數(shù) 這里簡單的把keyPath打印了出來
override class func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
        print(keyPath)
 }

3.然后我們試著改變一下sex的值

someone.sex = 1

因為我們觀察的時候選擇了觀察新值([.new])所以。我們會在observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) 里收到sex的新值1,如果大家沒有收到的話。檢查一下屬性是否正確使用了修飾符。
4.釋放
一定要在不需要觀察的時候釋放這個觀察者

deinit {
       some.removeObserver(self)
}

總結(jié)

觀察者使用起來API非常簡單,但是一定要注意防止造成循環(huán)引用。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容