0:KVO的使用步驟
// cc監(jiān)聽了aa的name屬性的改變 options: 是一個(gè)枚舉
[aa addObserver:cc forKeyPath:@"name" options: NSKeyValueObservingOptionOld context:nil];
// cc得實(shí)現(xiàn)監(jiān)聽方法
當(dāng)監(jiān)聽到object的keyPath屬性發(fā)生了改變
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context{
NSLog(@"監(jiān)聽到%@對(duì)象的%@屬性發(fā)生了改變, %@", object, keyPath, change);
}
1:KVO本質(zhì)
1:基本原理
kvo是利用runtime來實(shí)現(xiàn)的;當(dāng)某個(gè)類的屬性對(duì)象第一次被
觀察時(shí),系統(tǒng)就會(huì)在運(yùn)行期動(dòng)態(tài)的創(chuàng)建該類的一個(gè)子類,
在這個(gè)子類中重寫基類中任何被觀察屬性的setter方法,子
類在該屬性的set方法中調(diào)用_NSSetIntValueAndNotify函數(shù)
(該函數(shù)根據(jù)類set方法參數(shù)的類型而不同,該方法可以通過
p (IMP)<返回的地址>看到,在這個(gè)函數(shù)中實(shí)現(xiàn)真正的通知
機(jī)制,如果;如果原類為Person,那么生成的子類名為
NSKVONotifying_Person;每個(gè)類對(duì)象中都有一個(gè)isa指針指
向當(dāng)前類,當(dāng)一個(gè)類對(duì)象的第一次被觀察,那么系統(tǒng)會(huì)偷偷
將isa指針指向動(dòng)態(tài)生成的子類,從而在給被監(jiān)控屬性賦值
時(shí)執(zhí)行的是子類的_NSSetIntValueAndNotify函數(shù),在
_NSSetIntValueAndNotify中先調(diào)用willChangeValueForKey:
與[super setXXX:]和 didChangevlueForKey:方法,在
一個(gè)被觀察屬性發(fā)生改變之前, willChangeValueForKey:一
定會(huì)被調(diào)用,這就 會(huì)記錄舊的值。而當(dāng)改變發(fā)生后,
didChangeValueForKey:會(huì)被調(diào)用,在didChangeValueForKey:中就會(huì)調(diào)用
繼而 observeValueForKey:ofObject:change:context: 也會(huì)被調(diào)用。
methodForSelector方法
實(shí)例對(duì)象調(diào)用該方法,會(huì)返回@selector里面方法的地址,
然后在控制臺(tái) p (IMP)<返回的地址> 這樣就可以看到方法的具體實(shí)現(xiàn)類、方法名;
NSKVONotifying_Person里面的方法實(shí)現(xiàn)
-(Class)class{
//屏蔽內(nèi)部實(shí)現(xiàn),隱藏NSKVONotifying_Person的實(shí)現(xiàn)
}
-(Void)delloc{
//進(jìn)行收尾工作,觀察者
}
- (BOOL)_isKVOA{
//是否實(shí)現(xiàn)了kvo
return YES;
}
2:如何手動(dòng)觸發(fā)KVO
手動(dòng)調(diào)用willChangeValueForKey:和didChangeValueForKey:
3:直接修改對(duì)象的成員變量是否會(huì)觸發(fā)KVO
不會(huì),因?yàn)槌蓡T變量沒有實(shí)現(xiàn)set方法,所以不會(huì)觸發(fā)KVO;
想要觸發(fā)KVO的話需要這樣修改代碼
[self.person willChangeValueForKey:@"age"];
self.person->age = 10;
[self.person didChangeValueForKey:@"age"];