一、概述
KVO全稱KeyValueObserving呢岗,是蘋果提供的一套事件通知機制本昏。允許對象監(jiān)聽另一個對象特定屬性的改變,并在改變時接收到事件痢缎。對于基本數(shù)據(jù)類型是觀察值的變化胁勺,但對于指針類型(OC中對象都是指針),是觀察指針的地址是否變化独旷。
二署穗、KVO使用三步驟
1.注冊觀察者
- (void)addObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options context:(nullable void *)context;
2.監(jiān)聽方法,KVO會回調(diào)該方法方法來通知觀察者嵌洼。
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
- 當(dāng)觀察者不需要監(jiān)聽時案疲,需要移除監(jiān)聽
- (void)removeObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath context:(nullable void *)context
三、解讀
1.注冊方法
-
observer
:觀察者對象麻养,這個對象必須實現(xiàn)observeValueForKeyPath:ofObject:change:context:
方法褐啡,以響應(yīng)屬性的修改通知。 -
keyPath
:被監(jiān)聽的屬性鳖昌。這個值不能為nil春贸。 -
options
:監(jiān)聽選項,參數(shù)是一個枚舉類型遗遵。
options | 描述 |
---|---|
NSKeyValueObservingOptionNew |
提供屬性的新值 |
NSKeyValueObservingOptionOld |
提供屬性的舊值 |
NSKeyValueObservingOptionInitial |
觀察最初的值(在注冊觀察服務(wù)時會調(diào)用一次觸發(fā)) |
NSKeyValueObservingOptionPrior |
分別在值修改前后觸發(fā)方法(即一次修改有兩次觸發(fā)) |
-
context
:任意的額外數(shù)據(jù)萍恕,我們可以將這些數(shù)據(jù)作為上下文數(shù)據(jù),它會傳遞給觀察者對象的observeValueForKeyPath:ofObject:change:context:方法车要。
在調(diào)用addObserver方法后允粤,KVO并不會對觀察者進行強引用,所以需要注意觀察者的生命周期翼岁,否則會導(dǎo)致觀察者被釋放帶來的Crash类垫。
2. 監(jiān)聽方法
-
keyPath
:即被觀察的屬性,與參數(shù)object相關(guān)琅坡。 -
object
:keyPath所屬的對象悉患。 -
change
:這是一個字典,它包含了屬性被修改的一些信息榆俺。這個字典中包含的值和我們在添加觀察者時設(shè)置的options參數(shù)相呼應(yīng)售躁。 -
context
:這個值即是添加觀察者時傳遞的數(shù)據(jù)。
3. 調(diào)用方式
1.直接調(diào)用set方法茴晋,或者通過屬性的點語法間接調(diào)用
2.使用KVC的setValue:forKey:
方法
3.需要注意:
對于容器類陪捷,例如NSMutableArray在調(diào)用 addObject或removeObject 系列方法時,不會觸發(fā)KVO诺擅。為了實現(xiàn)容器類的 KVO市袖,官方為我們提供了如下方法:
- (NSMutableArray *)mutableArrayValueForKey:(NSString *)key
通過對該方法返回的數(shù)組進行增刪操作可以觸發(fā)KVO。
為什么會這樣呢烁涌?
1.開頭筆者提到過苍碟,對于指針對象酒觅,KVO本質(zhì)上是監(jiān)聽指針的地址是否變化。
數(shù)組在調(diào)用它的 addObject微峰、removeObject 系列方法時阐滩,雖然數(shù)組內(nèi)部發(fā)生了變化,但是數(shù)組的地址并沒有改變县忌。所以掂榔,不會觸發(fā)KVO。
2.調(diào)用mutableArrayValueForKey
這個方法症杏,會返回一個代理對象装获。(你可以理解為被觀察數(shù)組的深拷貝的對象)。至于深拷貝厉颤,淺拷貝的問題穴豫,筆者準備單獨展開一期進行論述。
3.當(dāng)對這個代理對象進行增刪等操作后逼友,會立刻對這個代理對象進行一次深拷貝精肃,并將源數(shù)組的指針指向這個新拷貝出來的數(shù)組。(可能有點繞帜乞,仔細縷一下)司抱。這樣被觀察的數(shù)組指針地址就發(fā)生了變化,從而觸發(fā)KVO黎烈。
最后提一下习柠,RAC的監(jiān)聽機制和KVO是一樣的。所以照棋,用RAC監(jiān)聽數(shù)組资溃,也可以采用這種方式