參考鏈接:
http://tech.glowing.com/cn/implement-kvo/ 手動實現(xiàn)KVO
1.addObserver:forKeyPath:options:context:各個參數(shù)的作用分別是什么调窍,observer中需要實現(xiàn)哪個方法才能獲得KVO回調(diào)抑胎?
// 添加鍵值觀察
/*1 觀察者,負責(zé)處理監(jiān)聽事件的對象
2 觀察的屬性
3 觀察的選項
4 上下文
*/
[self.personaddObserver:selfforKeyPath:@"name"options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOldcontext:@"Person Name"];
observer中需要實現(xiàn)一下方法:
// 所有的 kvo 監(jiān)聽到事件哄酝,都會調(diào)用此方法
/*1. 觀察的屬性
2. 觀察的對象
3. change 屬性變化字典(新/舊)
4. 上下文礁蔗,與監(jiān)聽的時候傳遞的一致
*/
- (void)observeValueForKeyPath:(NSString*)keyPath ofObject:(id)object change:(NSDictionary*)change context:(void*)context;
2.如何手動觸發(fā)一個value的KVO
所謂的“手動觸發(fā)”是區(qū)別于“自動觸發(fā)”:
自動觸發(fā)是指類似這種場景:在注冊 KVO 之前設(shè)置一個初始值鳖眼,注冊之后特铝,設(shè)置一個不一樣的值惶傻,就可以觸發(fā)了棍郎。
想知道如何手動觸發(fā),必須知道自動觸發(fā) KVO 的原理:
鍵值觀察通知依賴于 NSObject 的兩個方法:willChangeValueForKey:和didChangevlueForKey:银室。在一個被觀察屬性發(fā)生改變之前涂佃,willChangeValueForKey:一定會被調(diào)用,這就 會記錄舊的值蜈敢。而當(dāng)改變發(fā)生后辜荠,observeValueForKey:ofObject:change:context:會被調(diào)用,繼而didChangeValueForKey:也會被調(diào)用抓狭。如果可以手動實現(xiàn)這些調(diào)用伯病,就可以實現(xiàn)“手動觸發(fā)”了。
那么“手動觸發(fā)”的使用場景是什么否过?一般我們只在希望能控制“回調(diào)的調(diào)用時機”時才會這么做狱从。
具體做法如下:
如果這個value是 表示時間的self.now,那么代碼如下:最后兩行代碼缺一不可叠纹。
//? 手動觸發(fā) value 的KVO季研,最后兩行代碼缺一不可。
//@property (nonatomic, strong) NSDate *now;
- (void)viewDidLoad {? ??
[superviewDidLoad]; ?
_now = [NSDatedate]; ? ? ? ? ? ? ? ? ? ? [selfaddObserver:selfforKeyPath:@"now"options:NSKeyValueObservingOptionNewcontext:nil];NSLog(@"1");? ? [selfwillChangeValueForKey:@"now"];// “手動觸發(fā)self.now的KVO”誉察,必寫与涡。NSLog(@"2");? ? [selfdidChangeValueForKey:@"now"];// “手動觸發(fā)self.now的KVO”,必寫。NSLog(@"4");
}
但是平時我們一般不會這么干驼卖,我們都是等系統(tǒng)去“自動觸發(fā)”氨肌。“自動觸發(fā)”的實現(xiàn)原理:
比如調(diào)用setNow:時酌畜,系統(tǒng)還會以某種方式在中間插入wilChangeValueForKey:怎囚、didChangeValueForKey:和observeValueForKeyPath:ofObject:change:context:的調(diào)用。
大家可能以為這是因為setNow:是合成方法桥胞,有時候我們也能看到有人這么寫代碼:
- (void)setNow:(NSDate*)aDate {? ?
[selfwillChangeValueForKey:@"now"];// 沒有必要_now = aDate;? ?
[selfdidChangeValueForKey:@"now"];// 沒有必要
}
這完全沒有必要恳守,不要這么做,這樣的話贩虾,KVO代碼會被調(diào)用兩次催烘。KVO在調(diào)用存取方法之前總是調(diào)用willChangeValueForKey:,之后總是調(diào)用didChangeValueForkey:缎罢。