KVO的定義
當(dāng)指定的對象的屬性被修改時(shí),允許對象接收通知的機(jī)制。
觀察對象的屬性時(shí)软族,要指定觀察屬性的名稱,還有一些其他的選項(xiàng)(比如残制,將新/舊值都發(fā)給我)
“我想要觀察你的fido屬性立砸,如果它發(fā)生了變化就通知我”
當(dāng)setFido方法被調(diào)用時(shí),被觀察的對象就會發(fā)送消息給你:
“我的fido屬性有了一個(gè)新值”
KVO的好處
KVO機(jī)制很適合model模型和view視圖之間的通訊
例如:
模型類A創(chuàng)建屬性數(shù)據(jù)初茶,在控制器中創(chuàng)建觀察者颗祝,一旦屬性發(fā)生改變觀察者就收到通知,KVO再在控制器使用回調(diào)方法中處理實(shí)現(xiàn)視圖B的更新
KVO的代碼實(shí)現(xiàn)
基本實(shí)現(xiàn)
[logger addObserver:self forKeyPath:@“l(fā)astTime” options:NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOld context:nil];
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
NSString *oldValue = [change objectForKey:NSKeyValueObservingOptionOld];
NSString *newValue = [change objectForKey:NSKeyValueObservingOptionNew];
}
使用context
當(dāng)某個(gè)對象注冊為觀察者時(shí)恼布,需要傳遞指針作為context螺戳。當(dāng)接收變化的通知時(shí),context會隨通知一起發(fā)送折汞。
可以根據(jù)context判斷是子類的通知還是父類的通知
static int contextForKVO
[logger addObserver:self forKeyPath:@“fido” options:0 context:&contextForKVO];
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
if(context != &contextForKVO){
[super observeValueForKeyPath:keyPath ofObject:object change:change context:(void *)context];
} else {
// 處理變化
}
}
顯式觸發(fā)通知
如果使用存取方法來設(shè)置屬性倔幼,那么系統(tǒng)會自動通知觀察者。
如果不使用存取方法爽待,可以通過以下方法顯式觸發(fā)通知损同。
[self willChangeValueForKey:@“l(fā)astTime”];
_lastTime = now;
[self didChangeValueForKey”@“l(fā)astTime”];
獨(dú)立的屬性
不觀察_lastTime而想觀察_lastTimeString
[logger addObserver:self forKeyPath:@“l(fā)astTimeString” options:NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOld context:nil];
//告訴系統(tǒng)_lastTime會影響_lastTimeString
+ (NSSet *)KeyPathsForValuesAffectingLastTimeString {
return [NSSet setWithObject:@"lastTime"];
}
這樣,當(dāng)_lastTime發(fā)生變化時(shí)鸟款,觀察者會收到_lastTimeString改變的通知揖庄。
KVO的實(shí)現(xiàn)原理
如果向某個(gè)對象發(fā)送addObserver:forKeyPath:options:context: 消息,這個(gè)方法可以:
- 決定被觀察對象的類欠雌,并使用 objc_allocateClassPair() 函數(shù)給這個(gè)類定義一個(gè)新的子類KVONotifying_BNRTowel
- 改變對象的isa指針蹄梢,指向新的子類
- 覆蓋被觀察對象的存取器,發(fā)送KVO消息。
- (void)setLocation:(NSPoint)locatiton {
[self willChangeValueForKey:@"location"];
[super setLocation:location];
[self didChangeValueForKey:@"location"];
}
這個(gè)新的子類以及方法都會在運(yùn)行時(shí)使用運(yùn)行時(shí)函數(shù)定義禁炒。