15.键值编码KVC、键值观察KVO
2021-12-27 本文已影响0人
LucXion
键值编码是Cocoa的标准组件,允许开发者通过名字(键)访问属性,
valueForKeyPath 与 valueForKey
NSArray *arr = @[@{@"city":@"beijing",@"person":@"Zh"},@{@"city":@"chengdu",@"student":@"Li"}];
id result = [arr valueForKeyPath:@"city"];// 可以包含嵌套关系,用句点分开
id result2 = [arr valueForKey:@"city"];
// 打印结果都是 beijing,chengdu
NSLog(@"result = %@,result2 = %@",[result description],[result2 description]);
// 假如一个对象没有numbers属性,那么KVC系统会按顺序搜索如下方法是否实现,用第一个找到的方法来返回值
// 无论是否声明在.h文件中,函数的实现返回值为Void类型,返回值 = nil
getNumbers、numbers、isNumbers;
// 命名为_numbers、_isNumbers、numbers、isNumbers的实例变量,KVC会直接访问ivar,一般最好避免这种行为,直接访问实例变量破坏了封装原则,使代码更脆弱,通过覆盖+ (BOOL)accessInstanceVariablesDirectly方法并返回NO可以避免这种行为。
KVO
只要通过存取的方式修改实例变量,那么所有的观察机制都会自动生效,不需要付出任何成本。
KVO和容器类
如果要观察容器内对象的改变,一般可以先观察容器,在添加对象后观察对象,在删除对象后停止观察。
KVO如何实现
键值观察通知依赖于NSObject的两个方法,willChangeValueForKey: 和didChangeValueForKey:,当发生改变后observeValueForKeyPath:ofObject:change: context:会被调用。
这是通过
方法混写
来实现的:第一次对一个对象调用addObserver: forKeyPath: options: context:,框架会创建这个类的KVO子类,并将被观察对象转化为新子类的对象,这种继承和方法是在运行时实现的,前提是必须使用KVC命名约定。KVO混写不容易发现,它会复写class方法,返回原来的类,但有时我们能看到NSKVONotifying_MyClass而不是MyClass的调用。
在存在复杂的相互依赖关系或复杂的类继承层次的地方避免使用KVO,用委托或NSNotification的方式比较合适。