iOS下KVO使用過程中的陷阱

KVO,全稱為Key-Value Observing赊堪,是iOS中的一種設(shè)計模式,用于檢測對象的某些屬性的實時變化情況并作出響應(yīng)。網(wǎng)上廣為流傳普及的一個例子是利用KVO檢測股票價格的變動這個例子作為掃盲入門還是可以的椅贱,但是當(dāng)應(yīng)用場景比較復(fù)雜時懂算,里面的一些細(xì)節(jié)還是需要改進的,里面有多個地方存在crash的危險庇麦。本文旨在逐步遞進深入地探討出一種目前比較健壯穩(wěn)定的KVO實現(xiàn)方案犯犁,彌補網(wǎng)上大部分教程的不足!

首先女器,假設(shè)我們的目標(biāo)是在一個UITableViewController內(nèi)對tableview的contentOffset進行實時監(jiān)測,很容易地使用KVO來實現(xiàn)為住诸。
在初始化方法中加入:
[_tableView addObserver:self forKeyPath:@"contentOffset" options:NSKeyValueObservingOptionNew context:nil];

在dealloc中移除KVO監(jiān)聽:
[_tableView removeObserver:self forKeyPath:@"contentOffset" context:nil];

添加默認(rèn)的響應(yīng)回調(diào)方法:

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context{

   [self doSomethingWhenContentOffsetChanges];
}```

好了驾胆,KVO實現(xiàn)就到此完美結(jié)束了,拜拜贱呐。丧诺。。開個玩笑奄薇,肯定沒這么簡單的驳阎,這樣的代碼太粗糙了,當(dāng)你在controller中添加多個KVO時馁蒂,所有的回調(diào)都是走同上述函數(shù)呵晚,那就必須對觸發(fā)回調(diào)函數(shù)的來源進行判斷。判斷如下:
  • (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {

    if (object == _tableView && [keyPath isEqualToString:@"contentOffset"]) {

    [self doSomethingWhenContentOffsetChanges];
    }
    };```

你以為這樣就結(jié)束了嗎沫屡?答案是否定的饵隙!我們假設(shè)當(dāng)前類(在例子中為UITableViewController)還有父類,并且父類也有自己綁定了一些其他KVO呢沮脖?我們看到金矛,上述回調(diào)函數(shù)體中只有一個判斷,如果這個if不成立勺届,這次KVO事件的觸發(fā)就會到此中斷了驶俊。但事實上,若當(dāng)前類無法捕捉到這個KVO免姿,那很有可能是在他的superClass饼酿,或者super-superClass...中,上述處理砍斷了這個鏈养泡。合理的處理方式應(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];}
}```

 
這樣就結(jié)束了嗎嗜湃?答案仍舊是否定的。潛在的問題有可能出現(xiàn)在dealloc中對KVO的注銷上澜掩。KVO的一種缺陷(其實不能稱為缺陷购披,應(yīng)該稱為特性)是,當(dāng)對同一個keypath進行兩次removeObserver時會導(dǎo)致程序crash肩榕,這種情況常常出現(xiàn)在父類有一個kvo刚陡,父類在dealloc中remove了一次惩妇,子類又remove了一次的情況下。不要以為這種情況很少出現(xiàn)筐乳!當(dāng)你封裝framework開源給別人用或者多人協(xié)作開發(fā)時是有可能出現(xiàn)的歌殃,而且這種crash很難發(fā)現(xiàn)。不知道你發(fā)現(xiàn)沒蝙云,目前的代碼中context字段都是nil氓皱,那能否利用該字段來標(biāo)識出到底kvo是superClass注冊的,還是self注冊的勃刨?
回答是可以的波材。我們可以分別在父類以及本類中定義各自的context字符串,比如在本類中定義context為@"ThisIsMyKVOContextNotSuper";然后在dealloc中remove observer時指定移除的自身添加的observer身隐。這樣iOS就能知道移除的是自己的kvo廷区,而不是父類中的kvo,避免二次remove造成crash贾铝。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末隙轻,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子垢揩,更是在濱河造成了極大的恐慌玖绿,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,948評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件叁巨,死亡現(xiàn)場離奇詭異镰矿,居然都是意外死亡,警方通過查閱死者的電腦和手機俘种,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,371評論 3 385
  • 文/潘曉璐 我一進店門秤标,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人宙刘,你說我怎么就攤上這事苍姜。” “怎么了悬包?”我有些...
    開封第一講書人閱讀 157,490評論 0 348
  • 文/不壞的土叔 我叫張陵衙猪,是天一觀的道長。 經(jīng)常有香客問我布近,道長垫释,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,521評論 1 284
  • 正文 為了忘掉前任撑瞧,我火速辦了婚禮棵譬,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘预伺。我一直安慰自己订咸,他們只是感情好曼尊,可當(dāng)我...
    茶點故事閱讀 65,627評論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著脏嚷,像睡著了一般骆撇。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上父叙,一...
    開封第一講書人閱讀 49,842評論 1 290
  • 那天神郊,我揣著相機與錄音,去河邊找鬼趾唱。 笑死屿岂,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的鲸匿。 我是一名探鬼主播,決...
    沈念sama閱讀 38,997評論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼阻肩,長吁一口氣:“原來是場噩夢啊……” “哼带欢!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起烤惊,我...
    開封第一講書人閱讀 37,741評論 0 268
  • 序言:老撾萬榮一對情侶失蹤乔煞,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后柒室,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體渡贾,經(jīng)...
    沈念sama閱讀 44,203評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,534評論 2 327
  • 正文 我和宋清朗相戀三年雄右,在試婚紗的時候發(fā)現(xiàn)自己被綠了空骚。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,673評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡擂仍,死狀恐怖囤屹,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情逢渔,我是刑警寧澤肋坚,帶...
    沈念sama閱讀 34,339評論 4 330
  • 正文 年R本政府宣布,位于F島的核電站肃廓,受9級特大地震影響智厌,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜盲赊,卻給世界環(huán)境...
    茶點故事閱讀 39,955評論 3 313
  • 文/蒙蒙 一铣鹏、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧哀蘑,春花似錦吝沫、人聲如沸呻澜。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,770評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽羹幸。三九已至,卻和暖如春辫愉,著一層夾襖步出監(jiān)牢的瞬間栅受,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,000評論 1 266
  • 我被黑心中介騙來泰國打工恭朗, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留屏镊,地道東北人。 一個月前我還...
    沈念sama閱讀 46,394評論 2 360
  • 正文 我出身青樓痰腮,卻偏偏與公主長得像而芥,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子膀值,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,562評論 2 349

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