Write in the first【写在最前】
开发过程中,最常见的就是程序的流程取决于你所使用的各种变量和属性的值,根据变量和属性的值确定后面运行的代码。
学好「获取类中属性的变化」这一模块是开发重要部分之一,
目地:为了解决在开发过程中,由需求改变引发的各种蛋疼、繁琐的问题。
本篇文章主要从【KVC & KVO 使用场景相关】学习总结。
在「时间 & 知识 」有限内,总结的文章难免有「未全、不足 」的地方,还望各位好友指出,以提高文章质量。
目录:
- 引导
- KVC 概论
- KVC 常用方法
- KVC 对多种数据类型的支持
- KVC 实现原理
- KVC 基本使用
1.KVC 简单赋值 & 取值
2.KVC 访问私有成员变量
3.KVC 字典转模型- KVO 概论
- KVO 使用步骤
- KVO 实现原理
- KVO 手动发送通知机制
引导
我们有多种方式获取对象的改变。例如,使用委托、通知获取值的改变。如果需要观察多个属性的变化,使用委托或通知会产生大量代码,一个更好用来观察属性变化的方法是使用 键值监听(Key Value Observing,简称KVO),Apple 在自己的软件中大量使用 KVO。使用 KVO 跟踪单个属性或集合(如数组)的变化非常高效,键值观察建立在 键值编码(Key Value Coding,简称KVC) 基础上,也就是任何你想使用 KVO 监听的属性必须符合键值编码。KVO 只需要在观察者方法中添加代码,不需要修改被观察文件内代码,这一点和委托、通知不同。
KVC 和 KVO 提供了一个强大高效的方式来编写代码,学习 KVO 前必须先掌握 KVC,所以 我们按实用开发技巧一点点剖析它。
KVC 概论
KVC(全称 key-value-coding
)即键值编码。KVC 的操作方法由NSKeyValueCoding
非正式协议提供,而NSObject(NSKeyValueCoding)
就实现了这个协议,也就是说ObjC中几乎所有的对象都支持 KVC 操作,它是一种不通过存取方法(Setter、Getter
),而通过属性名称字符串(key
)间接访问类属性(实例变量)的机制。
KVC 常用方法
KVC 常用的方法如下:
- 赋值
|
|
- 获取值
|
|
KVC 对多种数据类型的支持
首先要说的是对于基本数据类型的属性,KVC 的这几个方法会自动装箱和拆箱。其次,KVC 也支持数组和字典等集合数据。这里了解不多,不做过多总结,有兴趣可参考:KVC/KVO原理详解及编程指南
简单示例:KVC 自动类型转换
如:模型类定义的属性是 float money
KVC 实现原理
1、[item setValue:@"白开水ln简书" forKey:@"name"];
- 1.首先去模型中查找有没有
setName
,若有,直接调用赋值[self setName:@"白开水ln简书"]
。 - 2.若无,去模型中查找有没有
name
属性,若有,直接访问属性赋值name = value
。 - 3.若无,再去模型中查找有没有
_name
成员变量,若有,直接访问属性赋值_name = value
。 - 4.找不到,就会直接报找不到的错误(
valueForUndefinedKey:
)。
2、[item setValuesForKeysWithDictionary:dict];
1.遍历字典中所有
key
。2.去模型中查找有没有对应的属性。
1234[dict enumerateKeysAndObjectsUsingBlock:^(id _Nonnull key, id _Nonnull value, BOOL * _Nonnull stop) {// 2.去模型中查找有没有对应属性 KVC[item setValue:value forKey:key];}];
KVC 基本使用
KVC 简单赋值 & 取值
|
|
区别:forKey:
和 forKeyPath:
1、forKeyPath
包含了所有 forKey
的功能
2、forKeyPath
进行内部的点语法,层层访问内部的属性
3、注意:key
值一定要在属性中找到,开发中最好使用forKeyPath
。
KVC 取值
KVC 访问私有成员变量
|
|
注意:上面的 keyPath
写age 或 _age都可以,KVC 会自动去查找。
KVC 字典转模型
简单示例:
开发中不建议使用
setValuesForKeysWithDictionary:
(把字典中所有值给模型的属性赋值)问题1:如果服务器多返回几个数据
Key
,在模型中系统找不到就会报错。1reason: '[<LNPerson 0x100304730> valueForUndefinedKey:]: this class is not key value coding-compliant for the key nam.
解决:重写系统方法 setValue:forUndefinedKey:
,就不会有报错信息了。
补充:什么时候重写系统方法?
1、想给系统方法添加额外功能 2、不想要系统方法实现
问题2:如果模型中带有模型型,
setValuesForKeysWithDictionary
不能用。
解决:思路,拿到每一个模型属性,去字典中取出对应的值,给模型赋值(提醒:从字典中取值,不一定要全部取出来)。
建议使用:MJExtension 字典转模型 和 Runtime(根据模型中属性,去字典中取出对应的value
给模型属性赋值)模型转成字典
1NSDictionary *dict = [person dictionaryWithValuesForKeys:@[@"name", @"money"]];
KVO 概论
KVO(Key-Value-Obersver
)即键值监听,利用一个key
来找到某个属性并监听其属性值得改变,当该属性发生变化时,会自动的通知观察者,这比通知中心需要post
通知来说,简单了许多。其实这也是一种典型的观察者模式。
KVO 使用步骤
- 给目标对象的属性添加观察者
- 在回调方法中监听属性的变化
- 移除观察者
具体代码如下:
KVO 实现原理
当一个类的属性被观察的时候,系统会通过runtime动态的创建一个该类的派生类,并且会在这个类中重写基类被观察的属性的setter方法,而且系统将这个类的isa指针指向了派生类,从而实现了给监听的属性赋值时调用的是派生类的setter方法。重写的setter方法会在调用原setter方法前后,通知观察对象值得改变。此外,派生类还重写了 dealloc 方法来释放资源。
可以看到重写的 setter 方法,给属性赋值的前后分别调用了两个方法。
而- (void)didChangeValueForKey:(NSString *)key;
会调用
KVO 手动发送通知机制
默认情况下,KVO 观察到属性变化系统会自动发送通知,但在某些情况下,你可能需要控制何时发送通知。例如:在某些情况下不需要发送通知,或将多个改变合并为一个通知发送。其实我们也可以手动,显式的调用上面两个方法,以使其具有通知机制。
举个示例:
期待
如果在阅读过程中遇到 error || new ideas,希望你能 messages 我,我会及时改正谢谢。
点击右上角的 喜欢 和 订阅Rss 按钮,可以收藏本仓库,并在 Demo 更新时收到邮件通知。