一、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方法前后,通知观察对象值得改变。
参考文章:
KVC,KVO实现原理