KVO提供一種機(jī)制,指定一個被觀察對象(例如A類),當(dāng)對象某個屬性(例如A中的字符串name)發(fā)生更改時(shí),對象會獲得通知,并作出相應(yīng)處理;【且不需要給被觀察的對象添加任何額外代碼,就能使用KVO機(jī)制】
在MVC設(shè)計(jì)架構(gòu)下的項(xiàng)目,KVO機(jī)制很適合實(shí)現(xiàn)mode模型和view視圖之間的通訊。
KVO 的實(shí)現(xiàn)依賴于 Objective-C 強(qiáng)大的 Runtime,其原理為:當(dāng)觀察某對象A時(shí),KVO機(jī)制動態(tài)創(chuàng)建一個對象A當(dāng)前類的子類,并為這個新的子類重寫了被觀察屬性keyPath的setter 方法。setter 方法隨后負(fù)責(zé)通知觀察對象屬性的改變狀況。其實(shí)在底層 runtime是動態(tài)的添加了一個類
isa 指針的作用:每個對象都有isa 指針,指向該對象的類,它告訴 Runtime 系統(tǒng)這個對象的類是什么。
self.car = [[Car alloc]init];
/*
1.注冊對象myKVO為被觀察者:
option中,
NSKeyValueObservingOptionOld 以字典的形式提供 “初始對象數(shù)據(jù)”;
NSKeyValueObservingOptionNew 以字典的形式提供 “更新后新的數(shù)據(jù)”;
*/
[self.car addObserver:self forKeyPath:@"num" options:NSKeyValueObservingOptionOld|NSKeyValueObservingOptionNew context:nil];
/* 2.只要object的keyPath屬性發(fā)生變化,就會調(diào)用此回調(diào)方法,進(jìn)行相應(yīng)的處理:UI更新:*/
-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context{
if([keyPath isEqualToString:@"num"] && object == self.car){
// 響應(yīng)變化處理:UI更新(label文本改變)
self.label.text = [NSString stringWithFormat:@"當(dāng)前的num值為:%@",[change valueForKey:@"new"]];
//上文注冊時(shí),枚舉為2個,因此可以提取change字典中的新、舊值的這兩個方法
NSLog(@"\n oldnum:%@-----newnum:%@",[change valueForKey:@"old"],[change valueForKey:@"new"]);
}
}
那么怎么證明KVO的底層是runtime呢?其實(shí)當(dāng)我們用到runtime的時(shí)候底層會隱藏的給我們創(chuàng)建一個繼承自我們要監(jiān)聽的這個類并且命名為 NSKVONotyfing_ 然后加要監(jiān)聽的類為名字的類
說起來有點(diǎn)繞口,這么說吧,用到我們這里就是一個叫NSKVONotyfing_Car的類,這里我已經(jīng)創(chuàng)建好了,怎么證明呢,首先刪除掉我創(chuàng)建的這個類,在observeValueForKeyPath這個方法打個斷點(diǎn)運(yùn)行,看控制臺的輸出即可
有圖為證