iOS的KVO、KVC
一:KVO
在实际的开发过程中,我们可能会遇到这种需求,就是需要根据一个对象某个属性值的改变,来作出不同的处理。但是实现起来比较麻烦,需要在很多地方进行判断处理,为了方便我们的开发,苹果推出了一个专门处理这种问题的解决方案,叫做KVO,负责监听属性值的改变、当发生改变的时候,可以及时的通知我们。
KVO的全程是Key-Value Observing,俗称“键值监听”,可以用于监听某个对象属性值的改变。
先来一个例子,下边在开始讲解原理。
KSPerson.h 文件
@interface KSPerson : NSObject
@property (nonatomic, strong) NSString * name;
@end
ViewController中:
#import "ViewController.h"
#import "KSPerson.h"
@interface ViewController ()
@property (nonatomic, strong) KSPerson * ks;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
_ks= [[KSPersonalloc]init];
_ks.name=@"Rose";
[_ks addObserver:self forKeyPath:@"name" options:NSKeyValueObservingOptionNew context:nil];
}
- (void)touchesBegan:(NSSet *)toucheswithEvent:(UIEvent*)event{
_ks.name=@"Jack";
}
- (void)observeValueForKeyPath:(NSString*)keyPathofObject:(id)objectchange:(NSDictionary *)changecontext:(void*)context{
NSLog(@"%@",change);
}
@end
当我们点击屏幕的时候,会触发observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context 方法。
原理:
我们使用xocde添加断点,打印类名:

根据打印的数据可以看出,添加KVO监听的对象的class类型变成了NSKVONotifying_KSPerson,不是我们想象中的KSPerson了。
这是因为利用RuntimeAPI动态生成一个子类,并且让instance对象的isa指向这个全新的子类
当修改instance对象的属性时,会调用Foundation的_NSSetXXXValueAndNotify函数
willChangeValueForKey:
父类原来的setter
didChangeValueForKey:
内部会触发监听器(Oberser)的监听方法( observeValueForKeyPath:ofObject:change:context:)
当调用set方法的时候,NSKVONotifying_KSPerson会先调用自己的Foundation _NSSetXXXValueAndNotifiy方法,查看_NSSet* AndNotify的存在:

_NSSet*ValueAndNotify的内部实现:
[self willChangeValueForKey:@"name"];
//原来的setter实现
[self didChangeValueForKey:@"name"];
调用willChangeValueForKey:
调用原来的setter实现
调用didChangeValueForKey:
didChangeValueForKey:内部会调用observer的observeValueForKeyPath:ofObject:change:context:方法
二:KVC
KVC的全称是Key-Value Coding,俗称“键值编码”,可以通过一个key来访问某个属性。
常见的API如下:
- (void)setValue:(id)value forKeyPath:(NSString *)keyPath;
- (void)setValue:(id)value forKey:(NSString *)key;
- (id)valueForKeyPath:(NSString *)keyPath;
- (id)valueForKey:(NSString*)key;

