KVC的简单实用

转自:http://www.jianshu.com/p/dd355fbfa029
kvc不经常使用,可能会忘记。转载一篇文章,留待以后温故而知新

KVC
介绍及简单使用
有了解过C#的同学都知道,C#高级语法中有一种机制叫“反射”
乍一听这名字还让人摸不着头脑,还以为是啥高科技(⊙﹏⊙)。往简单了讲,无非就只是用字符串动态去操作一个对象罢了-_-!。在C#的远房表亲OC中,也有这样功能的语法,操作起来可比C#简单的太多。这部分功能就叫KVC。
KVC:Key Value Coding,取其三个单词首字母浓缩而成。直白翻译过来就是键值编码,什么意思呢?简单来说,就是操作一个对象,也可以像操作字典一样,通过key来取值和赋值。
纳尼?真有这么神奇?接下来,我就带你走入KVC的奇妙世界
我们先创建一个HMPerson类来试验一下。
![Uploading 2147639-f259fa9e069ca402_075037.png . . .]
](http://upload-images.jianshu.io/upload_images/2405290-ac726ec28411e8e9.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
注:HM为前缀,在iOS开发中用来区分是哪个框架下的类。苹果推荐所有的非苹果官方开发者都以3个字母的作为前缀,2个字母的为苹果自身保留。这里为方便起见,接下来所有创建的类,我们都以HM开头
然后实例化HMPerson类的对象,此时,我们如果想要给它的name和age两个属性赋值和取值,就可以用点语法来操作,如图:


但是,这种点语法方式显得着实太low,接下来我们就用比较高大上的方式——KVC的方式来赋值和取值。我们先简单看看KVC里的几个方法:赋值

解释:第一个参数传入想赋的值,第二个参数传入想接收值的属性

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

解释:这种方式比较暴力,后头会解释

-(void)setValuesForKeysWithDictionary:(NSDictionary<NSString *, id>*)keyedValues;

取值:

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

解释:参数是传入你想取值的属性名 我们都知道,OC中任何对象都直接或间接的继承自NSObject,而在Foundation框架中,NSObject有个叫“NSKeyValueCoding”的分类,里面就包含了上面所有这些KVC方法。因此任何对象都可以通过KVC来取值和赋值,也就是说即使我们刚刚自己创建的Person类也有这些方法。 取值和赋值具体在代码中的应用如下:


我们发现KVC的方式使用起来也没任何问题。但是,很多同学会疑惑,为什么16要加个“@”符号呢?还有取值时为什么还要调用一下intValue方法呢?不这么写可不可以?答案是不行的,我们先看如果不这么写会怎样

143731y7z0i0l67wzeuzcm.png.thumb.jpg

此时发现,如果不按之前的写法会有一个错误以及一个警告。原因如下KVC中,赋值时传入的值都只能是对象类型,无法直接传入基本数据类型,因此,在给age属性赋值时,用了一个@符号,把16这个数字快速包装成了NSNumber类型(@加数字是快速创建NSNumber的语法)
通过KVC取值时,所有的返回值类型都是id类型(也即对象类型),因此无法直接用基本数据类型的变量来接收,必须调用其对应的类型转换代码先进行类型转换另外需要注意:KVC中所有的属性名都要以字符串的形式传入此时有同学会疑问了:“我勒个去!用KVC这么麻烦,还不如直接用点语法方便多了”,对,一般情况下是这样!但是,用KVC的方式有你意想不到优点!

KVC****的优点合集
****优点一:破门而入:与别人家的“私人专属”亲密接触
我们都知道,如果@property写在.h文件中,代表外界可以通过调用对应的setter和getter方法(或点语法)来访问对应的私有成员变量,但如果写在.m中,代表只允许本类中访问,其他地方访问不了。因此,我们给之前的Person类在.m文件中写一个延展,把.h文件的@property挪到.m的延展中。并且在.m文件中再加一个用@private修饰的成员变量如图:


此时,我们通过点语法来给属性赋值取值即会报错,如图

但是,如果是KVC方式,此时依然坚挺!

到此为止,KVC的好处之一得到完美体现:无论类中的成员是否私有,用KVC都可以强行“破门而入”,对它们正常取值和赋值。除此以外,还有个显而易见的好处是:KVC中不管你的成员变量是否加下划线,你用KVC取值和赋值时传入的属性名都可以不带下划线。**优点二:大大简化字典转模型代码 **很多时候,我们通过加载本地文件,或者网络请求会得到一个数据字典,为了方便调用,一般我们都会将这个字典转换为对应的模型类,但是,不用KVC的转换方法太过费劲,如图:先有一个HMPerson类

然后有一个字典,并且把字典里的元素赋值给HMPerson对象,如下图所示:

此时用点语法相当的麻烦,如果有100个属性,就必须一个元素一个元素地写100次。但用KVC的方式如何呢?我们看代码:

有同学看到这可能会疑惑了,KVC方式也没见得有多简便啊,代码看起来更多了!对,目前来说是这样子,但是大家仔细观察,setValue和ForKey两个参数里传入的key名是不是完全一样?如图:
Paste_Image.png

而这些Key,是不是刚好可以在遍历这个字典数据就可以获取到?如图:



大家看,在这个循环里,key好像就是我们用KVC的setValue:值 forKey:键 中需要传入的“键”,而dic[key]就是正方法中需要传入的“值”。

因此,我们可以将KVC实现字典转模型的方法直接用这个循环解决,如图:



看,此时是不是特别方便,代码特别简洁?哪怕以后字典有100项数据,对应实体类100个属性,再不用怕,就用这一个循环即可搞定! 但,这还不够简洁!

KVC提供了一套更简洁的操作方式,只需你传入一个字典,就可以帮你自动把字典里的每一项赋值给你实体类对应的属性,如图:


14.png

对,仅需调用setValuesForKeysWithDictionary方法,传入字典即可。这个方法内部,帮我们做了我们刚刚循环字典的操作,因此仅仅这一个方法就可完成字典数据转模型数据,从此,妈妈再也不用担心我写多余代码了!
注意:用setValuesForKeysWithDictionary或者自己写循环做字典数据转模型数据时,必须保证实体类的属性跟字典中的key名字一一对应,并且属性可以比字典多,但是绝对不能比字典的元素少!
KVC****疑问解密
****疑问解密1:

使用KVC是直接对成员变量赋值,还是调用了这个成员变量对应的setter和getter方法呢?为了解决这个疑问,我们给HMPerson类里加一个私有的成员变量name,并且给它写好对应的getter和setter方法,如图:

Paste_Image.png

然后用KVC的方式给name赋值和取值,如图:

Paste_Image.png

通过观察,我们发现用KVC来赋值时,对应的setter方法能被调用,用KVC来取值时,对应的getter方法也能被调用。因此小伙伴们不用担心KVC会破坏自己已经写好的属性封装规则。疑问解密1小分支:
如果没有getter方法和setter方法时,KVC是怎么找成员变量的呢?为了弄清这个问题,我们删掉name的getter和setter方法。如图:

Paste_Image.png

然后通过KVC方式赋值取值,会发现,依然可以赋值和取值成功。并且是给p对象的成员变量_name赋值的。如图:


Paste_Image.png

小伙伴们可能好奇的是,传入的Key是“name”,而赋值成功的是“_name”成员变量,那么如果,我同时有两个成员变量,一个叫“_name”,一个叫“name”,那KVC是给谁赋值的呢?为了搞清这个问题,我们先改良一下HMPerson类。

Paste_Image.png

然后,我们再次用KVC来调用,并且下一个断点看看,究竟是给哪个成员变量赋值的。如图:

Paste_Image.png

通过结果,我们发现,依然是对“_name”这个成员变量赋值的。这时候我们是否可以说,KVC永远是对带下划线的成员变量赋值的呢?那倒也未必,我们来继续看,假如此时给HMPerson删掉“_name”,只留“name”,又会是怎样。如图:

Paste_Image.png
Paste_Image.png

此时发现,用KVC赋值的就是这个不带下划线的成员变量(即name)了。因此,我们可以总结出,KVC赋值和取值的一套顺序:
用KVC取值或赋值时,会优先找这个属性对应的getter或setter方法来对这个属性赋值
如果找不到,则会查找带下划线的属性,如果找到则赋值
如果依然找不到,则会查找不带下划线的属性,如果找到则赋值
如果还是找不到,则报错(可以让它不报错,后文会详述)**疑问解密2:复合路径

**setValue:属性值 forKeyPath:属性路径 valueForKeyPath:属性名
复制代码
后面带Path的跟之前我们用的KVC有什么不同呢?我们来研究研究!假设此时有一个Dog类,而Person类里也有个属性是Dog类型的,叫pet,如图

Paste_Image.png
Paste_Image.png

如果此时实例化Person对象,要用KVC操作pet属性里的nickName属性就不太方便,只能先取出pet属性指向的Dog对象,再来操作nickName属性,如下:

Paste_Image.png

而带Path的方法,就是用来简化这种操作的,我们看

Paste_Image.png

因此,也就是说,如果需要操作访问一些“属性里的属性”时,就用带Path的方法来操作。** 疑问解密3:
**如果用KVC赋值时,某一个Key,类中没有会怎样?
例如:我们的HMPerson类现在没有salary属性。

Paste_Image.png

此时,通过KVC的方式赋值,运行时会崩溃

Paste_Image.png

因此,用KVC时传入的Key必须保证类中存在同名的属性。否则会运行时崩溃。那么如果我不希望运行时直接崩溃,而是来一个相对友好的提示,不要让它崩溃,该怎么办呢?我们就需要在HMPerson类里重写setValue:值 forUndefinedKey:键方法,这样,当用KVC对Person对象赋值了一个Key与属性对应不上的错误时,系统会自动调用这个方法,我们来试试看!如图:

Paste_Image.png
Paste_Image.png

此时,无论你输错多少次HMPerson对象不存在的属性时,都不会在运行时让程序崩溃,达到报错“友好”的目的。**总结
**KVC是一套方便我们用字符串来操作对象的机制,可以使得操作对象时跟操作字典一样的灵活。在字典转模型的领域中应用起来极为方便,并且KVC可以轻松的帮我们突破访问限制的一些问题,直接访问到私有成员。
但是同样,

KVC也有其缺点:例如在编码时很容易输错key导致问题,语法相较点语法而言也略微繁琐。但万事万物不也正如KVC一般既有其优点,也存在其不足之处,不是吗?

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,132评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,802评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,566评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,858评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,867评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,695评论 1 282
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,064评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,705评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,915评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,677评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,796评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,432评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,041评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,992评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,223评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,185评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,535评论 2 343

推荐阅读更多精彩内容