<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      [crash詳解與防護] KVO crash

      一、KVO介紹

            KVO(Key-Value Observing),鍵值監聽。它提供一種機制:指定的被觀察者的屬性被改變后,KVO就會通知觀察者,觀察者可以做出響應。

        KVO作用:利用KVO,很容易實現視圖組件和數據模型的分離。當數據模型的屬性值改變之后,作為監聽者的視圖組件就會被激發。這有利于業務邏輯和視圖展示的解耦合。

            KVO使用步驟:(1)注冊觀察,添加觀察者及屬性;(2)實現回調方法;(3)移除觀察。

       (1)注冊觀察:

      - (void)addObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options context:(void *)context
      /*
         observer:觀察者,也就是KVO通知的訂閱者。訂閱著必須實現observeValueForKeyPath:ofObject:change:context:方法
        keyPath:描述將要觀察的屬性,相對于被觀察者。 
        options:KVO的一些屬性配置;有四個選項。 
             options所包括的內容:
               NSKeyValueObservingOptionNew:change字典包括改變后的值;
               NSKeyValueObservingOptionOld:   change字典包括改變前的值; 
               NSKeyValueObservingOptionInitial:注冊后立刻觸發KVO通知; 
               NSKeyValueObservingOptionPrior:值改變前是否也要通知(這個key決定了是否在改變前改變后通知兩次).
        context: 上下文,這個會傳遞到訂閱著的函數中,用來區分消息,所以應當是不同的。 
      */

      (2)實現回調方法:

      - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context;
        /*
          keyPath:被監聽的keyPath , 用來區分不同的KVO監聽. 
           object: 被觀察修改后的對象(可以通過object獲得修改后的值). 
           change:保存信息改變的字典(可能有舊的值,新的值等) .
           context:上下文,用來區分不同的KVO監聽.
      */

      (3)移除觀察

       - (void)removeObserver:(NSObject *)anObserver forKeyPath:(NSString *)keyPath
        - (void)removeObserver:(NSObject *)observer     forKeyPath:(NSString *)keyPath  context:(void *)context
       /*
           注意:不要忘記解除注冊,否則會導致資源泄露 .
       */

      二、KVO使用舉例及注意事項

      //被觀察者 StockData.m
      #import "StockData.h"
      @interface StockData()
      @property(nonatomic, strong)NSString *stockName;
      @property(nonatomic, strong)NSString *price;
      @end
      
      //觀察者 SLVKVOController.m
      #import "SLVKVOController.h"
      #import "StockData.h"
      
      - (void)viewDidLoad {
          [super viewDidLoad];
          [self.stockData setValue:@"searph" forKey:@"stockName"];
          [self.stockData setValue:@"10.0" forKey:@"price"];
          [self.stockData addObserver:self forKeyPath:@"price"  options:NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOld context:SLVKVOContext];
      }
      
      -(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context {
          if(context == SLVKVOContext && object == self.stockData && [keyPath isEqualToString:@"price"]) {
              NSString * oldValue = [change objectForKey:NSKeyValueChangeOldKey];
              NSString * newValue = [change objectForKey:NSKeyValueChangeNewKey];
              self.myLabel.text = [NSString stringWithFormat:@"oldValue:%@ , newValue:%@",oldValue,newValue];
          } else {
              [super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
          }
      }
      
      -(void)dealloc {
          [self.stockData removeObserver:self forKeyPath:@"price" context:SLVKVOContext];
      }

      注意:

      (1)在第二步回調observeValueForKeyPath:函數中,要用else進行判斷調用super的對應函數。因為若當前函數無法處理對應的kvo,有可能super-class會有一些kvo的對應處理。

      (2)在第三步在dealloc函數中注銷觀察中,當對同一個keypath進行兩次removeObserver時會導致程序crash,這種情況常常出現在父類有一個kvo,父類在dealloc中remove了一次,子類又remove了一次的情況下。可以利用context字段來標識出到底kvo是superClass注冊的,還是self注冊的。我們可以分別在父類以及本類中定義各自的context字符串,然后在dealloc中remove observer時指定移除的自身添加的observer。這樣就能避免二次remove造成crash。

      三、KVO常見crash及防護方案

      KVO常見crash類型:

      (1)不能對不存在的屬性進行kvo觀測,否則會報crash:uncaught exception 'NSUnknownKeyException', reason: '[<StockData 0x600000203d50> setValue:forUndefinedKey:]: this class is not key value coding-compliant for the key stockName.'

      (2)訂閱者必須實現 observeValueForKeyPath:ofObject:change:context:方法,否則crash。

       Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: '<SLVKVOController: 0x7f811372ff70>: An -observeValueForKeyPath:ofObject:change:context: message was received but not handled.

      (3) 移除觀察,超過addObserver的次數就會 crash:Terminating app due to uncaught exception 'NSRangeException', reason: 'Cannot remove an observer <SLVKVOController 0x7ff8e8703100> for the key path "price" from <StockData 0x60800003d000> because it is not registered as an observer.'

       KVO crash解決方案:

       方案一、

        可以讓被觀察對象持有一個KVO的delegate,所有和KVO相關的操作均通過delegate來進行管理,delegate通過建立一張map來維護KVO整個關系。

      中間層delegate的代理工作:

      (1)如果出現KVO重復添加觀察者或者重復移除觀察者(KVO注冊觀察者與移除觀察者不匹配)的情況,delegate可以直接阻止這些非正常的操作。

      (2)被觀察者dealloc之前,可以通過delegate自動將與自己有關的KVO關系都注銷掉,避免了KVO的被觀察者dealloc時仍然注冊著KVO導致的crash。

      方案二、

        我們可以讓觀察者在注冊的過程中,將注冊信息一同記錄下來,然后使用某種方法在對象dealloc時,在記錄的信息里找到對應的觀察者,注銷觀察。

        此方案在宿主釋放過程中嵌入我們自己的對象,使得宿主釋放時順帶將我們的對象一起釋放掉,從而獲取dealloc的時機點。采用構建一個釋放通知對象,通過AssociatedObject方式連接到宿主對象,在宿主釋放時進行回調,完成注銷動作。

           具體的原理和代碼可以參照上一篇文章《[crash詳解與防護] NSNotification crash》。

       

       

       

       

       

             

      posted @ 2017-08-31 20:12  Xylophone  Views(2802)  Comments(0)    收藏  舉報
      主站蜘蛛池模板: 久久成人 久久鬼色| yyyy在线在片| 中文字幕亚洲人妻一区| 1024你懂的国产精品| 国产一二三五区不在卡| 国产成人无码网站| 亚洲宅男精品一区在线观看| 亚洲性日韩精品一区二区三区| 国产欧美日韩亚洲一区二区三区| 韩国三级+mp4| 国产精品亚洲А∨天堂免下载| 欧美日韩中文国产一区| 色噜噜狠狠一区二区三区果冻| 国产成人一区二区三区视频免费 | 国产91小视频在线观看| 亚洲乳大丰满中文字幕| 国产亚洲精品中文字幕| 成人无码视频| 亚洲精品日韩在线观看| 人妻有码av中文字幕久久琪| 久久国产自偷自免费一区| 狠狠色狠狠色综合日日不卡| 中国女人熟毛茸茸A毛片| 日韩精品在线观看一二区| 亚洲精品乱码久久久久久蜜桃不卡| 最新亚洲人成网站在线影院 | 一本色道久久88亚洲综合| 婷婷六月天在线| 韩国免费a级毛片久久| 国产大学生粉嫩无套流白浆| 激情伊人五月天久久综合| 亚洲一二三四区中文字幕| 欧美人与动牲交A免费观看| 日本黄色三级一区二区三区| 国产一级av在线播放| 国产精品三级中文字幕| 亚洲AV无码成H人动漫无遮挡| 狂野欧美性猛交免费视频| 久久国内精品自在自线91| 国产免费午夜福利757| 炉霍县|