前言設計
KVO鍵值觀察,咱們再熟悉不過了。可是大部分人對它的關注點可能都在對觀察某一個keyPath,會動態建立一個繼承該類的帶前綴NSKVONotifying_原類名的子類,而且在子類中重寫該key的setter方法這一邏輯。今天咱們來看一些可能平時不太注意的地方,而且討論一下KVO鍵值觀察爲何要建立子類來實現。code
觸發通知方式;server
(1)自動通知,這種應該是比較常見的,緣由在於NSObject類實現了NSKeyValueCoding協議,所以只要是繼承了NSObject類的對象經過KVC進行操做就能夠自動的通知到觀察者。對象
(2)手動通知,這就須要讓你的類重寫+ (BOOL)automaticallyNotifiesObserversForKey:(NSString *)key或者是+ (BOOL)automaticallyNotifiesObserversOf<key>方法,對於想要手動觸發通知的,能夠根據keyPath返回NO,而其對於其餘位置的keyPath,要返回父類的這個方法。例如屬性observingStr;繼承
+ (BOOL)automaticallyNotifiesObserversForKey:(NSString *)key { if ([key isEqualToString:@"observingStr"]) { return NO; } return YES; } + (BOOL)automaticallyNotifiesObserversOfObservingStr { return NO; }
手動觸發;開發
(1)要實現手動通知,你須要在值改變前調用 willChangeValueForKey: 方法,在值改變後調用 didChangeValueForKey: 方法。你能夠在發送通知前檢查值是否改變,若是沒有改變就不發送通知。關鍵在於willChangeValueForKey:以及didChangeValueForKey:這兩個方法,自動通知應該就是在子類重寫的setter中封裝好觸發通知的邏輯。get
(2)其實手動觸發通知有一個細節的地方,不知道有沒有人注意到,就是當你設置某個鍵值須要手動通知時,系統並無去動態建立帶前綴NSKVONotifying_原類名,你能夠經過rumtime的object_getClass(self),去驗證self的isa是否指向新類,答案是沒有。io
KVO鍵值觀察爲何要建立子類來實現?class
(1)上文也說了觸發鍵值觀察的關鍵方法willChangeValueForKey:和didChangeValueForKey:,咱們作個假設,假設蘋果KVO機制並無經過建立子類實現,而是在當前類實現。那麼會存在一個問題,就是開發者重寫該屬性的setter方法,而且並無去執行willChangeValueForKey:和didChangeValueForKey:兩個方法,就不會觸發通知觀察者。object
(2)有可能跟類設計的單一責任原則有關,子類自負責封裝觸發通知邏輯,其餘的一律無論(例如獲取舊值以及賦值新值都會執行父類的方法)。例如;
- (void)setObservingStr:(NSString *)observingStr { [self willChangeValueForKey:@"observingStr"]; NSLog(@"%@", NSStringFromClass(object_getClass(self))); //_observingStr = observingStr; //[self didChangeValueForKey:@"observingStr"]; } - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context { if ([keyPath isEqualToString:@"observingStr"]) { NSLog(@"newStr -- %@", change[NSKeyValueChangeNewKey]); } else { [super observeValueForKeyPath:keyPath ofObject:object change:change context:context]; } }
因爲重寫的setter方法沒有賦值新值,輸出newStr -- <null>;這也說明子類重寫的setter方法取值和賦值是經過父類的setter方法。
總結
本文所講的內容只是KVO的一部分,用於記錄平時研究一些技術的心得,瞭解更多的內容能夠查看這篇文章或者是上網查詢更多內容。