KVO
和NSNotificationCenter
都是iOS
中觀察者模式
的一種實現。區別在於,相對於被觀察者和觀察者之間的關係,KVO是一對一
的,而NSNotificationCenter是一對多
的。KVO
對被監聽對象無侵入性,不須要修改其內部代碼便可實現監聽。git
KVO
底層實現 KVO
是基於runtime
機制實現的,運用了一個isa-swizzling
技術。isa-swizzling
就是類型混合指針機制
, 將2個對象的isa
指針互相調換, 就是俗稱的黑魔法第一次被觀察
時,系統就會在運行期動態
地建立該類的一個派生類
,在這個派生類中重寫基類中任何被觀察屬性的setter
方法。派生類在被重寫的setter
方法內實現真正的通知機制
Person
,那麼生成的派生類名爲NSKVONotifying_Person
,每一個類對象中都有一個isa指針
指向當前類,當一個類對象第一次被觀察,那麼系統會偷偷將isa指針
指向動態生成的派生類,從而在給被監控屬性賦值時執行的是派生類的setter
方法NSObject
的兩個方法:willChangeValueForKey:
和didChangevlueForKey:
;在一個被觀察屬性發生改變以前,willChangeValueForKey:
必定會被調用,這就會記錄舊的值。而當改變發生後,didChangeValueForKey:
會被調用,繼而observeValueForKey:ofObject:change:context:
也會被調用KVO
的這套實現機制中蘋果還偷偷重寫了class
方法,讓咱們誤認爲仍是使用的當前類,從而達到隱藏生成的派生類KVO
手動調用willChangeValueForKey:
和didChangeValueForKey:
示例代碼以下:一、自動
//默認返回YES
+ (BOOL)automaticallyNotifiesObserversForKey:(NSString *)key{
if ([key isEqualToString:@"age"]) {
return NO;//不觀察age屬性值得變化
}
return YES;
}
二、手動
- (void)setName:(NSString *)name{
[self willChangeValueForKey:@"name"];
_name = name;
[self didChangeValueForKey:@"name"];
}
複製代碼
KVO
嗎 不會觸發KVO
,添加KVO
的Person
實例,實際上是NSKVONotyfing_Person
類在調用setter
方法,不是調用Person
的setter
方法,而是NSKVONotyfing_Person
的setter
方法,由於修改爲員變量不是setter
方法賦值Person
類進行了監聽,也建立了一個NSKVONotifying_Person
類,那麼會編譯經過麼 編譯經過,由於KVO
是運行時刻建立的,並不在編譯時刻,在編譯時刻只有一個NSKVONotifying_Person
,因此不報錯,能夠經過,可是此時KVO
起不了做用
附:個人博客地址github