一、Key-Value Coding: 鍵值編碼 (KVC)
方法調用:
// 對象屬性
// 類似: Person -> name
setValue: forKey:
// 對象的屬性或者 屬性的屬性...... 可見它已經包含前者.
// 類似: Person -> car -> name
setValue: forKeyPath:
// 字典轉模型 (key,屬性一一對應)
setValuesForKeysWithDictionary:
KVC主要通過isa-swizzling, 來實現其內部查找定位的. 默認的實現方法由NSOject提供
[object setValue:@"134567" forKey:@"uid"];
編譯器處理:
// 首先找到對應sel
SEL sel = sel_get_uid("setValue:forKey:");
// 根據object->isa找到sel對應的IMP實現指針
IMP method = objc_msg_lookup (object->isa,sel);
// 調用指針完成KVC賦值
method(object, sel, @"134567", @"uid");
KVC鍵值查找原理
setValue:forKey:搜索方式
1、首先搜索setKey:方法.(key指成員變量名, 首字母大寫)
2、上面的setter方法沒找到, 如果類方法accessInstanceVariablesDirectly返回YES.
那么按 _key, _isKey,key, iskey的順序搜索成員名.(NSKeyValueCodingCatogery中實現的類方法,
默認實現為返回YES)
3、如果沒有找到成員變量, 調用setValue:forUnderfinedKey:
valueForKey:的搜索方式
1、首先按getKey, key, isKey的順序查找getter方法, 找到直接調用.
如果是BOOL、int等內建值類型, 會做NSNumber的轉換.
2、上面的getter沒找到, 查找countOfKey, objectInKeyAtindex, KeyAtindexes格式的方法.
如果countOfKey和另外兩個方法中的一個找到,
那么就會返回一個可以響應NSArray所有方法的代理集合的NSArray消息方法.
3、還沒找到, 查找countOfKey, enumeratorOfKey, memberOfKey格式的方法. 如果這三個方法都找到,
那么就返回一個可以響應NSSet所有方法的代理集合.
4、還是沒找到, 如果類方法accessInstanceVariablesDirectly返回YES. 那么按 _key, _isKey, key, iskey的順序搜索成員名.
5、再沒找到, 調用valueForUndefinedKey.
二、Key-Value Observing 鍵值觀察(KVO)
KVO是基于KVC實現的,使用方法:
// 1.添加一個觀察者
[self.object addObserver:self forKeyPath:@"uid" options:NSKeyValueObservingOptionOld|NSKeyValueObservingOptionNew context:nil];
// 2.觀察者監聽到之后回調方法
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context {
}
// 3.移除觀察者, 類在銷毀前需要銷毀
[self.object removeObserver:self forKeyPath:@"uid"];
KVO底層實現:
當一個類的屬性被觀察的時候,系統會通過runtime動態的創建一個該類的派生類NSKVONotifying_xx,并且會在這個類中重寫基類被觀察的屬性的setter方法,而且系統將這個類的isa指針指向了派生類,從而實現了給監聽的屬性賦值時調用的是派生類的setter方法。重寫的setter方法會在調用原setter方法前后,通知觀察對象值得改變。
KVO原理
參考文章:
KVC,KVO實現原理