聊聊KVO、KVC(仅用作自己复习记录不喜勿喷)
KVC:Key Value Coding 键值编码
KVO:Key Value Observer 键值监听
可以先从KVO开始讲
我们开发中时常会需要对某个对象的某个属性值的变化进行监听,如果这个值发生遍话,就拿到这个事件,并做我们自己的逻辑处理。比如一个Person对象,内有一个int a属性,当a的值放生变化时,我们就可以感知到这个事件。
它的底层实现,其实是在添加监听者的时候,由runtime 动态的创建了一个Person子类,并且重写了该子类的setAge:方法,在重写这个方法时,分了几个步骤:
1、willChangeValueForKey:
2、_age = age
3、didChangeValueForKey:
内部会触发监听器(Observer)的监听方法(observeValueForKeyPath:ofObject:context:)
根据上述底层原理,可以推出以下结论,当然也可以写demo来验证
1、如果希望手动触发KVO,只需要手动调用willChangeValueForKey: 和didChangeValueForKey:
2、如果通过->箭头函数修改对象的成员变量值,不会触发KVO,因为这种方式并没有调用到set方法。
另外KVO还有个缺点,就是我们在写监听成员变量字段的时候,必须使用字符串来写,这样的话,系统就没有提示了,如果写错了,也不会有报错提示,这样会存在一定的隐患。
如何优化这个问题呢?
1、比如我们想监听age,之前的写法是@"age",那么如果我改成person.age这种就可以了。当然还有参数类型,需要知道这个参数是int float 还是NSString、或者其他。 那我们可以参考沙盒的方式,setInteger:forKey:,setFloat:forKey:,setObject: forKey:.
2、如果采取这种方式,接口可能太多了。可以试试通过runtime的接口 ivar_getTypeEncoding ivar_getName class_copyIvarList 这种获取成员变量列表,以及获取成员变量类型、然后进行比对,的方式来获取传入值的类型,知道类型以后,后续的操作,就可以按照1中的方式来做了。
下面再讲讲KVC的
KVC我们常用到的就是取值valueForKey和 设置值setValueForKey,比如我们想通过KVC更改person对象中age的值,那么就可以调用 [person setValue@18 ForKey@"age"]; 其实这里底层也是调用的set方法,拿到age字符串之后,先把第一个字母变大写,然后前面拼接 @"set", 变成set方法 setAge:。 可以试试,通过KVC的修改age,是可以触发KVO事件的。 然后取值,valueForKey也是同样原理调用的get方法
