![iOS开发:从零基础到精通](https://wfqqreader-1252317822.image.myqcloud.com/cover/796/26793796/b_26793796.jpg)
5.4 KVC
5.4.1 使用KVC赋值取值
1.KVC简介
KVC(Key-value coding)即键值编码,对应了NSKeyValueCoding类。NSKeyValueCoding类是对NSObject类进行的扩展,因此所有的类都可以使用NSKeyValueCoding类中定义的方法。其最基本的使用就是可以对对象属性进行赋值和取值,可以起到和点语法同样的效果。
在KVC中针对对象属性的赋值和取值提供了以下几种常用的方法。
- 赋值方法。
![](https://epubservercos.yuewen.com/D4B438/15253388904120706/epubprivate/OEBPS/Images/Figure-T141_16826.jpg?sign=1738911606-iQbSGsMMhhktIkSH2sloYqjnvn6CVJC5-0-b3a1dabbd1ae115e29a1f66b449f1741)
- 取值方法。
![](https://epubservercos.yuewen.com/D4B438/15253388904120706/epubprivate/OEBPS/Images/Figure-T141_16828.jpg?sign=1738911606-w9vonirKf2yFLyHTyaQzzjF2XW8s4R1Z-0-66fc40696982e3536a1d8bca530cce90)
2.示例代码
为了学习KVC的用法,可以预先定义两个类Person类和Dog类,其中Person类中有一个dog属性,如下所示。
- 在Person.h文件中添加如下代码。
![](https://epubservercos.yuewen.com/D4B438/15253388904120706/epubprivate/OEBPS/Images/Figure-T141_16830.jpg?sign=1738911606-DafmkJjJHdZjasSr76A5IJXADe9dJ6fo-0-3c790d8c0c924a5d5331adfc613eeacd)
- 在Dog.h文件中添加如下代码。
![](https://epubservercos.yuewen.com/D4B438/15253388904120706/epubprivate/OEBPS/Images/Figure-T141_16832.jpg?sign=1738911606-TbAOxeLbr1wKQzr0ok51JXji7KZzknm8-0-fae76ae125d34fa8a1e6162e8cc2068b)
下面的示例代码综合使用了KVC中有关赋值/取值的方法。
![](https://epubservercos.yuewen.com/D4B438/15253388904120706/epubprivate/OEBPS/Images/Figure-T141_16834.jpg?sign=1738911606-Fkz2jOVcDdmOMhEXhXSRxApBKJVMUd8D-0-d5b49ea9d6efe3cf4fbed6aec06e774b)
运行结果如图5-16所示。
![](https://epubservercos.yuewen.com/D4B438/15253388904120706/epubprivate/OEBPS/Images/Figure-P142_16954.jpg?sign=1738911606-wqgSdNHXnh9tf2ilaV4t5uQH7GMJzCes-0-81b6616081ca0d228552e9cd536e7349)
图5-16 运行结果
5.4.2 字典转模型
KVC除了最简单的对对象属性进行赋值和取值外,在NSKeyValueCoding类中,还提供了setValuesForKeysWithDictionary方法。该方法专门用于把一个字典转换成一个模型对象,但使用过程中要求字典中的键值和类中定义的属性名称必须完全一致。假如有不一致的情况,就需要在类的实现文件中,对名称不一致的键值需要使用setValue:forUndefinedKey:方法进行特殊处理。
![](https://epubservercos.yuewen.com/D4B438/15253388904120706/epubprivate/OEBPS/Images/Figure-T142_82853.jpg?sign=1738911606-tdLDs1oq0sg8HDVRqpkGHlE1zoZ5eJbl-0-19a3f16398a431fc2955aefa090a22b5)
下面的示例代码中,演示了如何使用KVC把一个字典对象转换成一个模型对象。如下所示是一个字典对象,在该字典对象中有3个键值对。
![](https://epubservercos.yuewen.com/D4B438/15253388904120706/epubprivate/OEBPS/Images/Figure-T142_16962.jpg?sign=1738911606-m0kdzN4doQgnXD0aylgivrXuzuFU6HA0-0-8d3683dec2f7fea3b178bce04dfdaa30)
然后,新建一个Person类,在Person.h文件中添加idNumber、name和age 3个属性,如下代码所示。注意,在字典中的键值名称与类的属性名称并不完全一一对应,在字典中的id键对应idNumber属性。
![](https://epubservercos.yuewen.com/D4B438/15253388904120706/epubprivate/OEBPS/Images/Figure-T142_16964.jpg?sign=1738911606-6GDW1g0Ascm0ZIHQp5toJ16zMCF3BOEX-0-d0d2d78d550cb2c0f5858bab11fff3d0)
在Person.m文件中,需要使用setValue:forUndefinedKey:方法对idNumber属性的赋值方法进行特殊处理,即字典中的id键值对的value需要赋值给idNumber属性。
![](https://epubservercos.yuewen.com/D4B438/15253388904120706/epubprivate/OEBPS/Images/Figure-T143_17088.jpg?sign=1738911606-XPEfOdzZRiZa0eAuoWMN128Q9w5NALb4-0-ec37136c4a889c9adfe98c5bcb525a2c)
在main()函数中,使用setValuesForKeysWithDictionary:方法来把一个字典转换成一个Person类的模型对象。
![](https://epubservercos.yuewen.com/D4B438/15253388904120706/epubprivate/OEBPS/Images/Figure-T143_17090.jpg?sign=1738911606-0EqnWErJn43vblUyyW2egxSqhS05r5xy-0-5f84b3216f95215a316228a38b9dd849)
运行结果如图5-17所示。
![](https://epubservercos.yuewen.com/D4B438/15253388904120706/epubprivate/OEBPS/Images/Figure-P143_17092.jpg?sign=1738911606-x8xy8SWNASyLqzo3dDWKzO60JTm6FA1R-0-e7919654eccc65d45b3fca3c45c799fe)
图5-17 运行结果
5.4.3 修改readonly的属性以及私有属性
KVC和点语法都可以用于对象属性的赋值,但是点语法只能给未被标记为readonly的属性进行赋值,而KVC是更加底层的技术,基本在类的定义中被标注为readonly的属性,也可以使用KVC进行修改。当然一般情况下,不建议修改readonly的属性。除此之外,通过runtime遍历出来的私有属性/私有变量也可以通过KVC进行赋值和取值。
为了验证KVC的这个功能,在之前创建的Person类中给idNumber属性添加readonly关键字,使其成为一个只读属性。
![](https://epubservercos.yuewen.com/D4B438/15253388904120706/epubprivate/OEBPS/Images/Figure-T144_17222.jpg?sign=1738911606-ZzI2o4ObTz31ndxkvNg2cZS4kDh8H1H1-0-256135908077df93aa723c115a60a130)
在Person.m中,重写init方法,在init方法中给只读属性赋初始值。
![](https://epubservercos.yuewen.com/D4B438/15253388904120706/epubprivate/OEBPS/Images/Figure-T144_17224.jpg?sign=1738911606-ilej2bzmpqM6vAFWSEYQwpso5PaT9cBS-0-6426f6f5040412d2b3ab14c67df63607)
由于idNumber属性是只读属性,因此不能够使用点语法来对其进行修改,下面的赋值方法编译器会报错,如图5-18所示。
![](https://epubservercos.yuewen.com/D4B438/15253388904120706/epubprivate/OEBPS/Images/Figure-P144_17226.jpg?sign=1738911606-B91gShGeoNlhbkfDUpMKzQn019Z4sohg-0-602059d8d94e27cda313d7ddec23d683)
图5-18 程序报错
假如一定要修改只读属性,可以使用KVC。如下所示,使用setValue:forKey:方法可以对只读属性idNumber的值强行进行修改。
![](https://epubservercos.yuewen.com/D4B438/15253388904120706/epubprivate/OEBPS/Images/Figure-T144_17230.jpg?sign=1738911606-AwN0RXo4EKobbymjsNAzekG7DaiDy35e-0-a450f3c2bb90c7b93f25c527b3b5827f)
运行结果如图5-19所示。可以看到只读属性的值被强行进行了修改。通常情况下,并不推荐这样做,不论是在系统框架中还是第三方框架中,被标注为只读的属性都是不建议程序员进行修改的,强行修改会出现一些不可预知的错误。
![](https://epubservercos.yuewen.com/D4B438/15253388904120706/epubprivate/OEBPS/Images/Figure-P144_17232.jpg?sign=1738911606-pFeuDgOPCyBsr9iMeXtHSR709vmQMAOb-0-78e789c9a1fb472ac5e674651bfdb8ce)
图5-19 运行结果