KVO 的實現原理
KVO是關于runtime機制實現的
當某個類的對象屬性第一次被觀察時,系統就會在運行期動態地創建該類的一個派生類,在這個派生類中重寫基類中任何被觀察屬性的setter方法。派生類在被重寫的setter方法內實現真正的通知機制
如果原類為Person,那么生成的派生類名為NSKVONotifying_Person
每個類對象中都有一個isa指針指向當前類,當一個類對象的第一次被觀察,那么系統就會偷偷講isa指針指向動態生成的派生類,從而在給被監控屬性復制是執行的是派生類的setter方法
鍵值觀察通知依賴于NSObject的兩個方法:willChangeValueForKey:和didChangeValueForKey:,在一個被觀察屬性發生改變之前,willChangeValueForkey:和didChangeValueForKey:;在一個被觀察屬性發生改變之前,willChangeValueForKey:一定會被調用,這就會記錄舊的值。而當改變發生后,didChangeValueForKey:會被調用,繼而observeValueForKey:ofObject:change:context:也會被調用
舉例偽代碼_NSSet*ValueAndNotify
- (void)setAge:(int)age
{_NSSetIntValueAndNotify();
}// 偽代碼
void _NSSetIntValueAndNotify()
{[self willChangeValueForKey:@"age"];[super setAge:age];[self didChangeValueForKey:@"age"];
}- (void)didChangeValueForKey:(NSString *)key
{// 通知監聽器,某某屬性值發生了改變[oberser observeValueForKeyPath:key ofObject:self change:nil context:nil];
}
KVC的實現原理
- KVC是Key Value Coding的簡稱。它是一種可以通過字符串的名字(key)來訪問類屬性的機制。而不是通過調用Setter、Getter方法訪問。KVC的方法定義在Foundation/NSKeyValueCoding中。
KVC使用的基本方法:
- (void)setValue:(nullableid)value forKey:(NSString*)key;//通過Key來設值
- (void)setValue:(nullableid)value forKeyPath:(NSString*)keyPath;//通過KeyPath來設值
- (nullableid)valueForKey:(NSString*)key;//直接通過Key來取值
- (nullableid)valueForKeyPath:(NSString*)keyPath;//通過KeyPath來取值
KVC 賦值 setValue:forKey:
- setValue:forKey:將鍵字符串key所對應的屬性的值設置為value。(按照setKey:、_setKey:順序查找方法)如果沒有找到Set方法的話,將調用方法setValue:ForUndefinedKey:。并拋出異常 NSUnknowKeyException
2.?若沒有找到Set方法,會調用對象的類方法+ (BOOL)accessInstanceVariablesDirectly;此方法返回YES時(默認返回YES),會按照_key,_iskey,key,iskey的順序搜索成員,然后賦值。
3.? 若都沒找到成員變量,將調用方法setValue:ForUndefinedKey:。并拋出異常 NSUnknowKeyException
KVC 取值值 valueForKey:
按先后順序搜索getKey:、key、isKey、三個
方法
,若某一個方法被實現,取到的即是方法返回的值,后面的方法不再運行。如果是BOOL或者Int等值類型, 會將其包裝成一個NSNumber對象。若這三個方法都沒有找到,則會調用+ (BOOL)accessInstanceVariablesDirectly方法判斷是否允許取成員變量的值。若返回NO,直接調用- (nullable id)valueForUndefinedKey:(NSString *)key方法,并拋出異常 NSUnknowKeyException
若返回YES,會按先后順序取_key、_isKey、 key、isKey
成員變量
的值。調用- (nullable id)valueForUndefinedKey:(NSString *)key方法。
補充
- KVC提供屬性值正確性驗證的API,它可以用來檢查set的值是否正確、為不正確的值做一個替換值或者拒絕設置新值并返回錯誤原因。
- - (BOOL)validateValue:(inout id __nullable * __nonnull)ioValue forKey:(NSString *)inKey error:(out NSError **)outError;
KVC中的異常.獲取值時找不到key- (nullable id)valueForUndefinedKey:(NSString *)key;
設值時找不到key- (void)setValue:(nullable id)value forUndefinedKey:(NSString *)key;
- 給不能設置nil的屬性設置了nil。
- 如果你在SetValue方法時面給Value傳nil,則會調用這個方法
- (void)setNilValueForKey:(NSString *)key;