iOS KVO理解

概述

  1. KVO全稱Key-Value-Observing,也叫鍵值監(jiān)聽(tīng),是一種觀察者設(shè)計(jì)模式.提供了一種機(jī)制,當(dāng)指定的對(duì)象的屬性被修改后,對(duì)象就會(huì)收到一個(gè)通知.也就是說(shuō)每次指定的被觀察的對(duì)象的屬性被修改后,KVO就會(huì)自動(dòng)通知相應(yīng)的觀察者.
  2. 優(yōu)勢(shì):可以降低兩個(gè)類(業(yè)務(wù)邏輯和視圖控制的類)之間的耦合性.也就是說(shuō)可以很容易的實(shí)現(xiàn)視圖組件和數(shù)據(jù)模型的分離.當(dāng)數(shù)據(jù)模型的屬性值改變之后作為監(jiān)聽(tīng)器的視圖組件就會(huì)被激發(fā)坝冕,激發(fā)時(shí)就會(huì)回調(diào)監(jiān)聽(tīng)器自身.
  3. 在Objective-C中要實(shí)現(xiàn)KVO則必須實(shí)現(xiàn)NSKeyValueObserving協(xié)議.但不用擔(dān)心,因?yàn)镹SObject已經(jīng)實(shí)現(xiàn)了該協(xié)議,因此幾乎所有的Objective-C對(duì)象都可以使用KVO.

KVO的方法

  1. 監(jiān)聽(tīng)方法
    - (void)addObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options context:(nullable void *)context;
    某一個(gè)對(duì)象(受虐狂,喜歡被人監(jiān)視),給自己添加一個(gè)監(jiān)聽(tīng)者(一般都是控制器本身self),讓監(jiān)聽(tīng)者監(jiān)聽(tīng)自身的某一個(gè)屬性. options就是要求監(jiān)聽(tīng)者記錄的信息. context就是要監(jiān)聽(tīng)者給自己添加一個(gè)標(biāo)記,以防止和別的對(duì)象的監(jiān)聽(tīng)混淆. 比如: 有兩個(gè)孩子讓家長(zhǎng)監(jiān)聽(tīng)他們做作業(yè).監(jiān)聽(tīng)者是家長(zhǎng),被監(jiān)聽(tīng)的對(duì)象是兩個(gè)孩子.
    參數(shù):
    • observer 觀察者,也就是KVO的訂閱者,訂閱者必須實(shí)現(xiàn)協(xié)議方法(下面有).
    • keyPath 描述將要觀察的對(duì)象的屬性,也就是被觀察者的屬性.
    • options KVO的屬性配置.
      • NSKeyValueObservingOptionNewchange字典包括改變后的值
      • NSKeyValueObservingOptionOldchange字典包括改變前的值
      • NSKeyValueObservingOptionInitial注冊(cè)后立刻觸發(fā)KVO通知
      • NSKeyValueObservingOptionPrior值改變前是否也要通知(這個(gè)key決定了是否在改變前改變后通知兩次)
    • context上下文趁尼,這個(gè)會(huì)傳遞到協(xié)議方法中,用來(lái)區(qū)分消息,處理不同的KVO.所以應(yīng)當(dāng)是不同的.
  2. 解除監(jiān)聽(tīng)
    - (void)removeObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath; 刪除指定keyPath的監(jiān)聽(tīng)器.
    - (void)removeObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath context:(nullable void *)context NS_AVAILABLE(10_7, 5_0);刪除特定上下文標(biāo)記的指定keyPath的監(jiān)聽(tīng)器.
  3. 回調(diào)監(jiān)聽(tīng)
    - (void)observeValueForKeyPath:(nullable NSString *)keyPath ofObject:(nullable id)object change:(nullable NSDictionary<NSKeyValueChangeKey, id> *)change context:(nullable void *)context;
    參數(shù):
    • keyPath 被監(jiān)聽(tīng)的keyPath
    • object 被監(jiān)聽(tīng)的修改后的對(duì)象,可以獲取修改的對(duì)象的屬性
    • change 保存信息改變的字典(可能有舊的值瓤逼,新的值等
    • context 上下文

使用步驟

  1. 注冊(cè)KVO監(jiān)聽(tīng).
  2. 實(shí)現(xiàn)代理方法.
  3. 移除監(jiān)聽(tīng).在dealloc方法中移除.

KVO使用注意事項(xiàng)

非常重要

  1. 當(dāng)你在同一個(gè)ViewController中添加多個(gè)KVO的時(shí)候,無(wú)論哪個(gè)KVO都是走- (void)observeValueForKeyPath:(nullable NSString *)keyPath ofObject:(nullable id)object change:(nullable NSDictionary<NSKeyValueChangeKey, id> *)change context:(nullable void *)context;回調(diào)方法.所以需要對(duì)想要的監(jiān)聽(tīng)對(duì)象進(jìn)行區(qū)分,以便指定不同的邏輯.
    這里是對(duì)_tableView對(duì)象的contentOffset屬性監(jiān)聽(tīng).
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
     if (object == _tableView && [keyPath isEqualToString:@"contentOffset"]) {
        [self doSomething];
     }
 }
  1. 我們假設(shè)當(dāng)前類(在例子中為UITableViewController)還有父類踢关,并且父類也有自己綁定了一些其他KVO呢伞鲫?我們看到,上述回調(diào)函數(shù)體中只有一個(gè)判斷签舞,如果這個(gè)if不成立秕脓,這次KVO事件的觸發(fā)就會(huì)到此中斷了柒瓣。但事實(shí)上,若當(dāng)前類無(wú)法捕捉到這個(gè)KVO吠架,那很有可能是在他的superClass芙贫,或者super-superClass...中,上述處理砍斷了這個(gè)鏈傍药。合理的處理方式應(yīng)該是這樣的:
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
    if (object == _tableView && [keyPath isEqualToString:@"contentOffset"]) {
        [self doSomethingWhenContentOffsetChanges];
} else {
        [super observeValueForKeyPath:keyPath ofObject:object change:change context:context]; }
}

但是這個(gè)是要自己搞清楚,父類中到底有沒(méi)有注冊(cè)KVO.如果監(jiān)聽(tīng)一個(gè)對(duì)象的兩個(gè)屬性,兩個(gè)屬性的改變時(shí)分開(kāi)執(zhí)行的,就會(huì)觸發(fā)兩次代理方法.如圖:

1.png
  1. KVO的一個(gè)特性,當(dāng)對(duì)同一個(gè)keyPath進(jìn)行多余一次的removeObserver的時(shí)候會(huì)導(dǎo)致程序crash.這種情況常常出現(xiàn)在父類有一個(gè)kvo磺平,父類在dealloc中remove了一次,子類又remove了一次的情況下拐辽。不要以為這種情況很少出現(xiàn)拣挪!當(dāng)你封裝framework開(kāi)源給別人用或者多人協(xié)作開(kāi)發(fā)時(shí)是有可能出現(xiàn)的,而且這種crash很難發(fā)現(xiàn).解決辦法就是我們可以分別在父類以及本類中定義各自的context字符串,這樣iOS就能知道移除的是自己的kvo俱诸,而不是父類中的kvo菠劝,避免二次remove造成crash.
  2. 把監(jiān)聽(tīng)到對(duì)象的屬性值改變賦值的時(shí)候,一定要注意監(jiān)聽(tīng)對(duì)象的值的類型.
    把監(jiān)聽(tīng)到對(duì)象的屬性值改變賦值的時(shí)候,一定要注意監(jiān)聽(tīng)對(duì)象的值的類型.
    把監(jiān)聽(tīng)到對(duì)象的屬性值改變賦值的時(shí)候,一定要注意監(jiān)聽(tīng)對(duì)象的值的類型.
    重要的事情說(shuō)三遍
  3. 如果監(jiān)聽(tīng)一個(gè)對(duì)象的多個(gè)屬性,任何一個(gè)屬性的改變都會(huì)走代理方法,也就是說(shuō)對(duì)屬性的監(jiān)聽(tīng),是分開(kāi)執(zhí)行的.

Demo 下載地址

https://github.com/mancongiOS/KVO.git

說(shuō)明

  1. KVO注意事項(xiàng)1,2,3條轉(zhuǎn)載于 編程小翁@博客園
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市睁搭,隨后出現(xiàn)的幾起案子闸英,更是在濱河造成了極大的恐慌,老刑警劉巖介袜,帶你破解...
    沈念sama閱讀 218,204評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件甫何,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡遇伞,警方通過(guò)查閱死者的電腦和手機(jī)辙喂,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,091評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)鸠珠,“玉大人巍耗,你說(shuō)我怎么就攤上這事〗ヅ牛” “怎么了炬太?”我有些...
    開(kāi)封第一講書(shū)人閱讀 164,548評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)驯耻。 經(jīng)常有香客問(wèn)我亲族,道長(zhǎng),這世上最難降的妖魔是什么可缚? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,657評(píng)論 1 293
  • 正文 為了忘掉前任霎迫,我火速辦了婚禮,結(jié)果婚禮上帘靡,老公的妹妹穿的比我還像新娘知给。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,689評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布涩赢。 她就那樣靜靜地躺著戈次,像睡著了一般。 火紅的嫁衣襯著肌膚如雪筒扒。 梳的紋絲不亂的頭發(fā)上朝扼,一...
    開(kāi)封第一講書(shū)人閱讀 51,554評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音霎肯,去河邊找鬼擎颖。 笑死,一個(gè)胖子當(dāng)著我的面吹牛观游,可吹牛的內(nèi)容都是我干的搂捧。 我是一名探鬼主播,決...
    沈念sama閱讀 40,302評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼懂缕,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼允跑!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起搪柑,我...
    開(kāi)封第一講書(shū)人閱讀 39,216評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤聋丝,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后工碾,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體弱睦,經(jīng)...
    沈念sama閱讀 45,661評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,851評(píng)論 3 336
  • 正文 我和宋清朗相戀三年渊额,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了况木。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,977評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡旬迹,死狀恐怖火惊,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情奔垦,我是刑警寧澤屹耐,帶...
    沈念sama閱讀 35,697評(píng)論 5 347
  • 正文 年R本政府宣布,位于F島的核電站椿猎,受9級(jí)特大地震影響惶岭,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜鸵贬,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,306評(píng)論 3 330
  • 文/蒙蒙 一俗他、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧阔逼,春花似錦、人聲如沸地沮。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,898評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至危融,卻和暖如春畏铆,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背吉殃。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,019評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工辞居, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人蛋勺。 一個(gè)月前我還...
    沈念sama閱讀 48,138評(píng)論 3 370
  • 正文 我出身青樓瓦灶,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親抱完。 傳聞我的和親對(duì)象是個(gè)殘疾皇子贼陶,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,927評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容

  • KVO 作為 iOS 中一種強(qiáng)大并且有效的機(jī)制,為 iOS 開(kāi)發(fā)者們提供了很多的便利巧娱;我們可以使用 KVO 來(lái)檢測(cè)...
    JzRo閱讀 940評(píng)論 0 2
  • 寫(xiě)在前面 程序設(shè)計(jì)語(yǔ)言中有各種各樣的設(shè)計(jì)模式(pattern)和與此對(duì)應(yīng)的反設(shè)計(jì)模式(anti-pattern),...
    Frankxp閱讀 4,926評(píng)論 0 23
  • 本文結(jié)構(gòu)如下: Why? (為什么要用KVO) What? (KVO是什么) How? ( KVO怎么用) Mo...
    等開(kāi)會(huì)閱讀 1,651評(píng)論 1 21
  • 本文由我們團(tuán)隊(duì)的 糾結(jié)倫 童鞋撰寫(xiě)老翘。 文章結(jié)構(gòu)如下: Why? (為什么要用KVO) What? (KVO是什么...
    知識(shí)小集閱讀 7,412評(píng)論 7 105
  • KCV 其實(shí)由于ObjC的語(yǔ)言特性趴樱,你根部不必進(jìn)行任何操作就可以進(jìn)行屬性的動(dòng)態(tài)讀寫(xiě),這種方式就是Key Value...
    TYM閱讀 1,059評(píng)論 0 4