#iOS笔记/复习笔记
KVO
KVO的全称是Key-Value Observing,俗称”键值监听”,可以用于监听摸个对象属性值得改变。
KVO原理
如果对象没有添加KVO监听那么它的isa指向的就是自己原来的类对象,如下图
当一个对象添加了KVO的监听时,当前对象的isa指针指向的就不是你原来的类,指向的是另外一个类对象,如下图
NSKVONotifying_DLPerson
- 是 Runtime动态创建的一个类,在程序运行的过程中产生的一个新的类;
- 是DLPerson的一个子类,superclass指向了DLPerson;
- 存在自己的 setAge:、class、dealloc、isKVOA...方法;
- 扩展,isa指针指向自己的元类(NSKVONotifying_DLPerson应该有自己的元类);
- 添加了KVO监听的对象,runtime动态创建一个新类NSKVONotifying_DLPerson,NSKVONotifying_DLPerson 是DLPerson的子类,DLPerson的实例对象的isa指针指向新类;
- 当我们DLperson的实例对象调用setAge方法时,实例对象的isa指针找到类对象,然后在类类对象中寻找相应的对象方法,也就找到了NSKVONotifying_DLPerson类的setAge方法;
- NSKVONotifying_DLPerson在setAge中添加了一些操作
[self willChangeValueForKey:@"age"];
[super setAge:age];
[self didChangeValueForKey:@"age"];
总结:
didChangeValueForKey:内部会调用observer的observeValueForKeyPath:ofObject:change:context:方法
KVC
KVC的全称key - value - coding,俗称”键值编码”,可以通过key来访问某个属性
setValue:forKey:的原理
accessInstanceVariablesDirectly用来判断是否可以直接访问成员变量
+ (BOOL)accessInstanceVariablesDirectly{
return YES; ///> 可以直接访问成员变量
// return NO; ///> 不可以直接访问成员变量,
///> 直接访问会报NSUnkonwKeyException错误
}
- 当我们设置
setValue:forKey:时 - 首先会查找
setKey:、_setKey:(按顺序查找) - 如果有直接调用
- 如果没有,先查看
accessInstanceVariablesDirectly方法 - 如果可以访问会按照
_key、_isKey、key、iskey的顺序查找成员变量 - 找到直接赋值
- 未找到报错
NSUnkonwKeyException错误
valueForKey:的原理
- kvc取值按照
getKey、key、iskey、_key顺序查找方法 - 存在直接调用
- 没找到同样,先查看
accessInstanceVariablesDirectly方法 - 如果可以访问会按照
_key、_isKey、key、iskey的顺序查找成员变量 - 找到直接赋值
- 未找到报错NSUnkonwKeyException错误
面试题
- iOS用什么方式实现对一个对象的KVO?(KVO的本质是什么?)
- 利用RuntimeAPI动态生成一个子类,并且让instance对象的isa指向这个全新的子类.
- 当修改instance对象的属性时,会调用Foundation的_NSSetXXXValueAndNotify函数
willChangeValueForKey: 父类原来的setter didChangeValueForKey:
- 内部会触发监听器(Oberser)的监听方法
(observeValueForKeyPath:ofObject:change:context:)
- 如何手动触发KVO?
手动调用
willChangeValueForKey:和didChangeValueForKey:
- 直接修改成员变量会触发KVO么?
不会触发KVO,因为直接修改成员变量并没有走set方法。
- 通过KVC会触发KVO么?
- 都会触发;
- KVC修改属性,属性都有set方法,因此会触发KVO;
- KVC修改成员变量,因为成员变量没有set方法,因此KVC是直接赋值,没有调用set方法,但是当这个成员变量被KVO监听后,通过KVC修改成员变量时会调用willChangeValueForKey,didChangeValueForKey,因此也会触发KVO;(可以在.m文件中添加这个两个方法进行验证,kvo不监听该成员变量时不会调用这两个方法,只有监听才会调用,ps必须是同一个成员变量)