iOS KVO crash 自修復技術實現與原理解析

KVO crash 自修復技術實現與原理解析

前言

【前言】KVO API設計很是不合理,因而有不少的KVO三方庫,好比 KVOController 用更優的API來規避這些crash,可是侵入性比較大,必須編碼規範來約束全部人都要使用該方式。有沒有什麼更優雅,無感知的接入方式?html

簡介

KVO crash 也是很是常見的 Crash 類型,在探討 KVO crash 緣由前,咱們先來看一下傳統的KVO寫發:git

#warning move this to top of .m file
//#define MyKVOContext(A) static void * const A = (void*)&A;
static void * const MyContext = (void*)&MyContext;

#warning move this to viewdidload or init method 
   // KVO註冊監聽:
   // _A 監聽 _B  的 @"keyPath"  屬性
   //[self.B  addObserver: self.A forKeyPath:@"keyPath" options:NSKeyValueObservingOptionNew context:MyContext];

- (void)dealloc {
   // KVO反註冊
   [_B removeObserver:_A forKeyPath:@"keyPath"];
}

// KVO監聽執行 
#warning — please move this method to  the class of _A  
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
   if(context != MyContext) {
       [super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
       return;
   }
   if(context == MyContext) {
   //if ([keyPath isEqualToString:@"keyPath"]) {
       id newKey = change[NSKeyValueChangeNewKey];
       BOOL boolValue = [newKey boolValue];
       
   }
}

看到如上的寫發,大概咱們就明白了 API 設計不合理的地方:github

B 須要作的工做太多,B可能引發Crash的點也太多:app

B 須要主動移除監聽者的時機,不然就crash:this

  • B 在釋放變爲nil後,hook dealloc時機
  • A 在釋放變爲nil後 不然報錯 Objective-C Thread 1: EXC_BAD_ACCESS (code=EXC_I386_GPFLT)

KVO的被觀察者dealloc時仍然註冊着KVO致使的crash阿里雲

B 不能移除監聽者A的時機,不然就crash:編碼

  • B沒有被A監聽
  • B已經移除A的監聽。

添加KVO重複添加觀察者或重複移除觀察者(KVO 註冊觀察者與移除觀察者不匹配)致使的crash。spa

我有幾張阿里雲幸運券分享給你,用券購買或者升級阿里雲相應產品會有特惠驚喜哦!把想要買的產品的幸運券都領走吧!快下手,立刻就要搶光了。設計

採起的措施:code

  • B添加A監聽的時候,避免重複添加,移除的時候避免重複移除。
  • B dealloc時及時移除 A
  • A dealloc時,讓 B 移除A。
  • 避免重複添加,避免重複移除。

報錯信息一覽:

2018-01-24 16:08:54.100667+0800 BootingProtection[63487:29487624] *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: '<CYLObserverView: 0x7fb287002fb0; frame = (0 0; 207 368); layer = <CALayer: 0x604000039360>>: An -observeValueForKeyPath:ofObject:change:context: message was received but not handled.

防crash措施

因而有不少的KVO三方庫,好比 KVOController 用更優的API來規避這些crash,可是侵入性比較大,必須編碼規範來約束全部人都要使用該方式。有沒有什麼更優雅,無感知的接入方式?

那即是咱們下面要講的 KVO crash 防禦機制。

相關文章
相關標籤/搜索