iOS消息傳遞之KVO

??KVO簡介:鍵值觀察,是基于鍵值編碼(KVC)的一種觀察模式。 是iOS中常用的一種消息傳遞機制。
??對接模式:發(fā)送者和接收者的關(guān)系為一對多的關(guān)系,一個發(fā)送者可以有多個接收者。
??使用鍵值觀察需要被觀察對象編寫符合KVC標(biāo)準(zhǔn)的存取方法,使用步驟分為以下三步:

  • 第一步:注冊成為KVO觀察者
  • 第二步:定義KVO的回調(diào)
  • 第三步:移除KVO觀察者
    ??第一步:調(diào)用注冊方法成為觀察者
[ObjectOfObserved addObserver:observerObject forKeyPath:@"example" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld context:nil];

KVO注冊方法參數(shù):

  • ObjectOfObserved:NSObject類型,為被觀察者對象
  • 參數(shù)Observer:NSObject類型,為觀察者對象,即要注冊成為觀察者的對象(既然是在觀察者的.m文件中實現(xiàn)的,那么該參數(shù)則為self)
  • 參數(shù)KeyPath:NSString類型,鍵路徑參數(shù),描述將要觀察的屬性,即被觀察者的屬性參數(shù)。(如:被觀察者有一個命名為example的屬性,而且你要觀察的正是這個屬性,那就設(shè)置這個參數(shù)為@"example")
  • 參數(shù)options:枚舉類型,有四個選項,標(biāo)識KVO希望變化如何傳遞給觀察者,可以使用"|"進行多選(這里觀察屬性變化的新值和舊值)

options枚舉:
1、NSKeyValueObservingOptionNew:該枚舉值保證KVO監(jiān)聽屬性的新內(nèi)容,當(dāng)屬性內(nèi)容變化時,KVO會記錄屬性的新內(nèi)容,這樣KVO回調(diào)方法中的參數(shù)change字典中包括改變后的值,可以通過KVO的監(jiān)聽回調(diào)方法獲取到屬性的新內(nèi)容
2、NSKeyValueObservingOptionOld:該枚舉值保證KVO監(jiān)聽屬性的原內(nèi)容,當(dāng)屬性內(nèi)容變化時,KVO會記錄屬性的原內(nèi)容,這樣KVO回調(diào)方法中的參數(shù)change字典包括改變前的值,可以通過KVO的監(jiān)聽回調(diào)方法獲取到屬性的原內(nèi)容
3、NSKeyValueObservingOptionInitial: 注冊后立刻觸發(fā)KVO通知,添加該枚舉后,即使屬性值沒有變化,也會調(diào)用KVO回調(diào)方法
4、NSKeyValueObservingOptionPrior:值改變前是否也要通知(這個key決定了是否在改變前改變后通知兩次)

  • 參數(shù)context:void類型指針,上下文內(nèi)存區(qū),通常設(shè)置為nil 。這個會傳遞到觀察者的函數(shù)中,用來區(qū)分不同的監(jiān)聽消息。

如何設(shè)置context:
可以參考這篇文章Key-Value Observing中《正確的上下文聲明》部分;以及這篇文章 kvo/gcd中關(guān)于context指針的賦值

??第二步:在觀察者的.m實現(xiàn)文件中定義KVO的回調(diào)方法

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

該方法是系統(tǒng)提供的觀察者實現(xiàn)鍵值觀察方法,作為觀察者,需要實現(xiàn)這個方法。當(dāng)被觀察的被觀察屬性發(fā)生變化時(這里的變化是指賦值操作,只要給屬性賦值就會調(diào)用,就算賦相同的內(nèi)容,也會調(diào)用),會自動調(diào)用這個方法。

KVO回調(diào)方法中參數(shù):

  • 參數(shù)keyPath:NSString類型,被監(jiān)聽的keyPath , 用來區(qū)分不同的KVO監(jiān)聽
  • 參數(shù)object:id類型,為被監(jiān)察的對象
  • 參數(shù)change:NSDictionary類型,保存被監(jiān)察者信息的字典
  • 參數(shù)context:void類型,上下文,用來區(qū)分不同的KVO監(jiān)聽

KVO回調(diào)方法操作:

  • 當(dāng)監(jiān)聽者監(jiān)聽了多個被監(jiān)聽者時,可以在回調(diào)方法中通過參數(shù)keyPath來判斷是哪個監(jiān)聽消息,```
    [keyPath isEqualToString:@"name"]
* 獲取被監(jiān)聽者對象```
    監(jiān)聽者對象類型 *變量名 = object;
  • 獲取被監(jiān)聽者內(nèi)容未變時的屬性對象```
    屬性對象類型 * old = [change objectForKey:NSKeyValueChangeOldKey];
* 獲取被監(jiān)聽者內(nèi)容已變時的屬性對象```
屬性對象類型 * new = [change objectForKey:NSKeyValueChangeNewKey];

??第三步:在觀察者的.m文件中的dealloc方法中移除觀察者

- (void)dealloc {
    // 調(diào)用移除觀察者的方法:- (void)removeObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath;
    [ObjectOfObserved removeObserver:Observer forKeyPath:@"example"];
}

KVO移除方法參數(shù):

  • ObjectOfObserved:NSObject類型,為被觀察者對象
  • 參數(shù)Observer:NSObject類型,為觀察者對象,即要注冊成為觀察者的對象(既然是在觀察者的.m文件中實現(xiàn)的,那么該參數(shù)則為self)
  • 參數(shù)KeyPath:NSString類型,鍵路徑參數(shù),即被觀察者的屬性參數(shù)。(如:被觀察者有一個命名為example的屬性,而且你要觀察的正是這個屬性,那就設(shè)置這個參數(shù)為@"example")

注:如果忘記解除移除監(jiān)察,會導(dǎo)致資源泄露

??拓展一: KVO手動設(shè)置
?KVO模型中,有兩種通知觀察者的方式,自動通知和手動通知。一般我們都用系統(tǒng)自動通知,文章開篇介紹的就是KVO自動通知。
?KVO手動通知的設(shè)置出了完成自動通知的三個步驟,需要在被觀察者的.m實現(xiàn)文件中重寫類方法:

+ (BOOL)automaticallyNotifiesObserversForKey:(NSString *)key {
    
}

返回NO時,告訴系統(tǒng)使用KVO手動通知;返回YES時,使用KVO自動通知,默認(rèn)為YES;
參數(shù)key為NSString類型,被監(jiān)聽的keyPath , 用來區(qū)分不同的KVO監(jiān)聽。
另外,在當(dāng)被監(jiān)聽的屬性發(fā)生變化時,需要調(diào)用屬性值將要改變的方法和屬性值已經(jīng)改變方法

// 手動通知在需要改變example變量的地方,使用

[self willChangeValueForKey:@"example"];

self.example = @"我是被監(jiān)聽的屬性,字符串類型的";

[self didChangeValueForKey:@"example"];


自動通知在需要改變example變量的地方,使用KVC設(shè)置屬性內(nèi)容的方法,而不是僅僅使用簡單賦值。

[self setValue:@"我是被監(jiān)聽的屬性,字符串類型的" forKey:@"example"];

手動改變屬性內(nèi)容時,我們需要在3個地方改變屬性的內(nèi)容值,即:請求結(jié)束時、連接出錯誤,線程被cancel。請在對應(yīng)的方法代碼中加入手動變值的語句。

??拓展二: KVC簡單介紹
可以參看這篇文章:iOS開發(fā)技巧系列---詳解KVC(我告訴你KVC的一切)

參考文章

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

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

  • 上半年有段時間做了一個項目,項目中聊天界面用到了音頻播放,涉及到進度條,當(dāng)時做android時候處理的不太好,由于...
    DaZenD閱讀 3,100評論 0 26
  • 本文結(jié)構(gòu)如下: Why? (為什么要用KVO) What? (KVO是什么) How? ( KVO怎么用) Mo...
    等開會閱讀 1,730評論 1 21
  • 本篇會對KVO的實現(xiàn)進行探究,不涉及太多KVO的使用方法,但是會有一些使用時的思考。 一、使用上的疑問 1.key...
    奮拓達閱讀 567評論 0 2
  • 本文由我們團隊的 糾結(jié)倫 童鞋撰寫。 文章結(jié)構(gòu)如下: Why? (為什么要用KVO) What? (KVO是什么...
    知識小集閱讀 7,484評論 7 105
  • 由于明天沒有時間,所以提前一天板繪一張圣誕卡,祝大家度過愉快的平安夜后,接著又有一個棒棒的圣誕節(jié)!
    TiBi閱讀 322評論 2 0

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