KVC和KVO

说到KVC不得不说SetGet

正常访问属性都是用Set方法和Get方法

但是苹果还提供了另外一种方法就是KVC全称Key-Value Coding 中文就是键值编码

简单点来说就是直接

valueForKeyvalueForKeyPath来获取属性的值

setValue forKey setValue forKeyPath来修改属性的值

相当于间接访问属性

这样的好处是可以访问私有属性

还有就是字典转模型

调用Set方法时

1
2
- (void)setValue:(id)value forKey:(NSString *)key;
- (void)setValue:(id)value forKeyPath:(NSString *)keyPath;

程序会先查找SetKey _SetKey

如果没有找到SetKey _SetKey

就会走+(BOOL)accessInstanceVariablesDirectly这个方法

这个方法是能不能访问成员变量

默认都是YES

当自己的私有变量不想让外部访问的时候可以重写这个方法返回NO

如果返回NO的话就会报错

1
- (void)setValue:(nullable id)value forUndefinedKey:(NSString *)key

返回 YES 的话

就会去遍历_key_isKeykeyisKey

还没有的话就会报错

1
- (void)setValue:(nullable id)value forUndefinedKey:(NSString *)key

调用Get方法时

1
2
- (nullable id)valueForKey:(NSString *)key;
- (nullable id)valueForKeyPath:(NSString *)keyPath;

程序会先查找getKey Key isKey _Key

如果没有找到getKey Key isKey _Key

就会走+(BOOL)accessInstanceVariablesDirectly这个方法

这个方法是能不能访问成员变量

默认都是YES

当自己的私有变量不想让外部访问的时候可以重写这个方法返回NO

如果返回NO的话就会报错

1
- (void)setValue:(nullable id)value forUndefinedKey:(NSString *)key

返回 YES 的话

就会去遍历_key_isKeykeyisKey

还没有的话就会报错

1
- (void)setValue:(nullable id)value forUndefinedKey:(NSString *)key

KVO的依赖于OC的Runtime来实现的,当观察者对象时,KVO机制动态创建一个对象A的子类(NSKVONotifying_A类),并为这个子类重写了被观察的属性的setter方法,setter方法会负责调用原来的setter方法前后,通知观察对象发生了变化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
//直接通过Key来取值
- (nullable id)valueForKey:(NSString *)key;

//通过Key来设值
- (void)setValue:(nullable id)value forKey:(NSString *)key;

//通过KeyPath来取值
- (nullable id)valueForKeyPath:(NSString *)keyPath;

//通过KeyPath来设值
- (void)setValue:(nullable id)value forKeyPath:(NSString *)keyPath;

//默认返回YES,表示如果没有找到Set<Key>方法的话,会按照_key,_iskey,key,iskey的顺序搜索成员,设置成NO就不这样搜索
+ (BOOL)accessInstanceVariablesDirectly;

//如果Key不存在,且KVC无法搜索到任何和Key有关的字段或者属性,则会调用这个方法,默认是抛出异常。
- (nullable id)valueForUndefinedKey:(NSString *)key;

//和上一个方法一样,但这个方法是设值。
- (void)setValue:(nullable id)value forUndefinedKey:(NSString *)key;

//如果你在SetValue方法时面给Value传nil,则会调用这个方法
- (void)setNilValueForKey:(NSString *)key;

KVC全称Key Value Observing 中文就是键值观察

听名字就能猜个大概

观察说明当值改变的时候就会告诉你

首先要注册观察者addObserver:forKeyPath:options:context:

然后实现observeValueForKeyPath:ofObject:change:context

最后需要移出观察removeObserver:forKeyPath

KVC原理

注册KVC之后

会生成一个NSKVONotifying_的类

该类继承于观察对象并将原来的对象的isa指向这个新类

并重写了class方法返回原类的名字

还有就是重写了Set方法

这样当调用Set方法的时候

这个新类就会知道

修改值之前会调用willChangeValueForKey:方法

修改值之后会调用didChangeValueForKey:方法

这两个方法最终都会被调用到observeValueForKeyPath:ofObject:change:context:里面

KVO和通知的区别

相同点:都是对象之间传递信息的一种机制,都需要注册移除

不同点:

KVO 是一对一,只支持属性的更改,只是用了Runtime动态创建一个心类,重写Set方法并通过协议的方法回调

通知是一对多,通知支持的类型更广,相当于广播,但是名字不能重复