(IOS)KVO

概述

KVO全稱為Key Value Observing,鍵值監(jiān)聽(tīng)機(jī)制,由NSKeyValueObserving協(xié)議提供支持,NSObject類繼承了該協(xié)議,所以NSObject的子類都可使用該方法。

KVO全稱KeyValueObserving,是蘋果提供的一套事件通知機(jī)制。允許對(duì)象監(jiān)聽(tīng)另一個(gè)對(duì)象特定屬性的改變,并在改變時(shí)接收到事件。由于KVO的實(shí)現(xiàn)機(jī)制,所以對(duì)屬性才會(huì)發(fā)生作用,一般繼承自NSObject的對(duì)象都默認(rèn)支持KVO。

KVO和NSNotificationCenter都是iOS中觀察者模式的一種實(shí)現(xiàn)。區(qū)別在于,相對(duì)于被觀察者和觀察者之間的關(guān)系,KVO是一對(duì)一的,而一對(duì)多的。KVO對(duì)被監(jiān)聽(tīng)對(duì)象無(wú)侵入性,不需要修改其內(nèi)部代碼即可實(shí)現(xiàn)監(jiān)聽(tīng)。

KVO可以監(jiān)聽(tīng)單個(gè)屬性的變化,也可以監(jiān)聽(tīng)集合對(duì)象的變化。通過(guò)KVC的mutableArrayValueForKey:等方法獲得代理對(duì)象,當(dāng)代理對(duì)象的內(nèi)部對(duì)象發(fā)生改變時(shí),會(huì)回調(diào)KVO監(jiān)聽(tīng)的方法。集合對(duì)象包含NSArray和NSSet。

基礎(chǔ)使用

使用KVO分為三個(gè)步驟:

通過(guò)addObserver:forKeyPath:options:context:方法注冊(cè)觀察者,觀察者可以接收keyPath屬性的變化事件。

在觀察者中實(shí)現(xiàn)observeValueForKeyPath:ofObject:change:context:方法,當(dāng)keyPath屬性發(fā)生改變后,KVO會(huì)回調(diào)這個(gè)方法來(lái)通知觀察者。

當(dāng)觀察者不需要監(jiān)聽(tīng)時(shí),可以調(diào)用removeObserver:forKeyPath:方法將KVO移除。需要注意的是,調(diào)用removeObserver需要在觀察者消失之前,否則會(huì)導(dǎo)致Crash。

注冊(cè)方法

在注冊(cè)觀察者時(shí),可以傳入options參數(shù),參數(shù)是一個(gè)枚舉類型。如果傳入NSKeyValueObservingOptionNew和NSKeyValueObservingOptionOld表示接收新值和舊值,默認(rèn)為只接收新值。如果想在注冊(cè)觀察者后,立即接收一次回調(diào),則可以加入NSKeyValueObservingOptionInitial枚舉。

還可以通過(guò)方法context傳入任意類型的對(duì)象,在接收消息回調(diào)的代碼中可以接收到這個(gè)對(duì)象,是KVO中的一種傳值方式。

在調(diào)用addObserver方法后,KVO并不會(huì)對(duì)觀察者進(jìn)行強(qiáng)引用,所以需要注意觀察者的生命周期,否則會(huì)導(dǎo)致觀察者被釋放帶來(lái)的Crash。

監(jiān)聽(tīng)方法

觀察者需要實(shí)現(xiàn)observeValueForKeyPath:ofObject:change:context:方法,當(dāng)KVO事件到來(lái)時(shí)會(huì)調(diào)用這個(gè)方法,如果沒(méi)有實(shí)現(xiàn)會(huì)導(dǎo)致Crash。change字典中存放KVO屬性相關(guān)的值,根據(jù)options時(shí)傳入的枚舉來(lái)返回。枚舉會(huì)對(duì)應(yīng)相應(yīng)key來(lái)從字典中取出值,例如有NSKeyValueChangeOldKey字段,存儲(chǔ)改變之前的舊值。

change中還有NSKeyValueChangeKindKey字段,和NSKeyValueChangeOldKey是平級(jí)的關(guān)系,來(lái)提供本次更改的信息,對(duì)應(yīng)NSKeyValueChange枚舉類型的value。例如被觀察屬性發(fā)生改變時(shí),字段為NSKeyValueChangeSetting。

如果被觀察對(duì)象是集合對(duì)象,在NSKeyValueChangeKindKey字段中會(huì)包含NSKeyValueChangeInsertion、NSKeyValueChangeRemoval、NSKeyValueChangeReplacement的信息,表示集合對(duì)象的操作方式。

KVO實(shí)現(xiàn)步驟

1.注冊(cè)觀察者(為被觀察這指定觀察者以及被觀察者屬性)

/*

options: 有4個(gè)值,分別是:

NSKeyValueObservingOptionOld 把更改之前的值提供給處理方法

NSKeyValueObservingOptionNew 把更改之后的值提供給處理方法

NSKeyValueObservingOptionInitial 把初始化的值提供給處理方法,一旦注冊(cè),立馬就會(huì)調(diào)用一次。通常它會(huì)帶有新值,而不會(huì)帶有舊值。

NSKeyValueObservingOptionPrior 分2次調(diào)用。在值改變之前和值改變之后。

*/

//注冊(cè)一個(gè)監(jiān)聽(tīng)器用于監(jiān)聽(tīng)指定的key路徑[self.person addObserver:self forKeyPath:@"name" options:NSKeyValueObservingOptionNew context:nil];

2.實(shí)現(xiàn)回調(diào)方法

//當(dāng)key路徑對(duì)應(yīng)的屬性值發(fā)生改變時(shí),監(jiān)聽(tīng)器就會(huì)回調(diào)自身的監(jiān)聽(tīng)方法,如下- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)contex

}

3.觸發(fā)回調(diào)方法

注意:路徑keyPath請(qǐng)參考上一篇KVO中的說(shuō)明

4.移除觀察者

//刪除指定的key路徑監(jiān)聽(tīng)器

[self.person removeObserver:self forKeyPath:@"name"];

//刪除指定的key路徑監(jiān)聽(tīng)器,只是多了context參數(shù)

[self.person removeObserver:self forKeyPath:@"name" context:nil];

KVO的主要應(yīng)用場(chǎng)景

應(yīng)用場(chǎng)景:當(dāng)數(shù)據(jù)模型的數(shù)據(jù)發(fā)生改變時(shí),視圖組件能動(dòng)態(tài)的更新,及時(shí)顯示數(shù)據(jù)模型更新后的數(shù)據(jù)。

比如:監(jiān)聽(tīng)scrollView的contentOffset屬性,來(lái)完成用戶滾動(dòng)時(shí)動(dòng)態(tài)改變某些控件的屬性實(shí)現(xiàn)效果,包括漸變導(dǎo)航欄、下拉刷新控件等效果。

KVO的實(shí)現(xiàn)原理簡(jiǎn)要說(shuō)明

KVO 是基于 runtime 機(jī)制實(shí)現(xiàn)的 當(dāng)某個(gè)類的屬性對(duì)象第一次被觀察時(shí),系統(tǒng)就會(huì)在運(yùn)行期動(dòng)態(tài)地創(chuàng)建該類的一 個(gè)派生類,在這個(gè)派生類中重寫基類中任何被觀察屬性的 setter 方法。派生類在 被重寫的 setter 方法內(nèi)實(shí)現(xiàn)真正的通知機(jī)制。

如果原類為 Person,那么生成的派生類名為 NSKVONotifying_Person 每個(gè)類對(duì)象中都有一個(gè) isa 指針指向當(dāng)前類,當(dāng)一個(gè)類對(duì)象的第一次被觀察,那么 系統(tǒng)會(huì)偷偷將 isa 指針指向動(dòng)態(tài)生成的派生類,從而在給被監(jiān)控屬性賦值時(shí)執(zhí)行的是派生類的 setter 方法。

鍵值觀察通知依賴于 NSObject 的兩個(gè)方法willChangeValueForKey:,didChangevlueForKey:

在一個(gè)被觀察屬性發(fā)生改變之前, willChangeValueForKey: 一定會(huì)被調(diào)用,這就 會(huì)記錄舊的值。而當(dāng)改變發(fā)生后,didChangeValueForKey: 會(huì)被調(diào)用,

繼而observeValueForKey:ofObject:change:context: 也會(huì)被調(diào)用。

補(bǔ)充:KVO 的這套實(shí)現(xiàn)機(jī)制中蘋果還偷偷重寫了 class 方法,讓我們誤認(rèn)為還是使用的當(dāng)前類,從而達(dá)到隱藏生成的派生類。

注意點(diǎn)

KVO的addObserver和removeObserver需要是成對(duì)的,如果重復(fù)remove則會(huì)導(dǎo)致NSRangeException類型的Crash,如果忘記remove則會(huì)在觀察者釋放后再次接收到KVO回調(diào)時(shí)Crash。

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

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

  • 什么是KVO KVO (Key-Value Observing) 是 Objective-C 對(duì)觀察者設(shè)計(jì)模式的一...
    壯骨閱讀 377評(píng)論 0 0
  • 上一篇:iOS-KVC淺談 前言:KVO 作為 KVC 的同袍兄弟,功能更強(qiáng)大,聊聊 KVO。 一、KVO 簡(jiǎn)介 ...
    夢(mèng)蕊dream閱讀 809評(píng)論 0 0
  • 導(dǎo)語(yǔ): KVO全稱Key Value Observing,直譯為鍵值觀察。KVO 作為 iOS 中一種強(qiáng)大并且有效...
    xianminxiao閱讀 1,202評(píng)論 0 2
  • 一、概述 二、KVO基本原理 1.KVO是基于runtime機(jī)制實(shí)現(xiàn)的2.當(dāng)某個(gè)類的屬性對(duì)象第一次被觀察時(shí),系統(tǒng)就...
    ForScanf閱讀 769評(píng)論 0 0
  • 1.KVO,即:Key-Value Observing,它提供一種機(jī)制,當(dāng)指定的對(duì)象的屬性被修改后,則對(duì)象就會(huì)接受...
    BEYOND黃閱讀 1,636評(píng)論 0 6

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