Objective-C KVC使用,包你看懂会用

KVC:Key Value Coding,取其三个单词首字母浓缩而成。直白翻译过来就是键值编码,什么意思呢?简单来说,就是操作一个对象,也可以像操作字典一样,通过key来取值和赋值。

我们先创建一个HMPerson类来试验一下。

然后实例化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方法呢?不这么写可不可以?答案是不行的,我们先看如果不这么写会怎样
    • 原因如下 
      1. KVC中,赋值时传入的值都只能是对象类型,无法直接传入基本数据类型,因此,在给age属性赋值时,用了一个@符号,把16这个数字快速包装成了NSNumber类型(@加数字是快速创建NSNumber的语法)
      2. 通过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对象,如下图所示:
    • 因此,我们可以将KVC实现字典转模型的方法直接用这个循环解决
    • KVC提供了一套更简洁的操作方式,只需你传入一个字典,就可以帮你自动把字典里的每一项赋值给你实体类对应的属性,如图:
    • 对,仅需调用setValuesForKeysWithDictionary方法,传入字典即可。这个方法内部,帮我们做了我们刚刚循环字典的操作,因此仅仅这一个方法就可完成字典数据转模型数据,从此,妈妈再也不用担心我写多余代码了!

      注意:用setValuesForKeysWithDictionary或者自己写循环做字典数据转模型数据时,必须保证实体类的属性跟字典中的key名字一一对应,并且属性可以比字典多,但是绝对不能比字典的元素少!

    • KVC
      **疑问解密

      疑问解密
      1:
      **

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

      • 然后用KVC的方式给name赋值和取值,如图:
      • 通过观察,我们发现用KVC来赋值时,对应的setter方法能被调用,用KVC来取值时,对应的getter方法也能被调用。
        因此小伙伴们不用担心KVC会破坏自己已经写好的属性封装规则。
        疑问解密1小分支:

        如果没有getter方法和setter方法时,KVC是怎么找成员变量的呢?
        为了弄清这个问题,我们删掉name的getter和setter方法。然后通过KVC方式赋值取值,会发现,依然可以赋值和取值成功。并且是给p对象的成员变量_name赋值的。如图:

      • 小伙伴们可能好奇的是,传入的Key是“name”,而赋值成功的是“_name”成员变量,那么如果,我同时有两个成员变量,一个叫“_name”,一个叫“name”,那KVC是给谁赋值的呢?
        为了搞清这个问题,我们先改良一下HMPerson类。
        • 然后,我们再次用KVC来调用,并且下一个断点看看,究竟是给哪个成员变量赋值的。如图:
        • 通过结果,我们发现,依然是对“_name”这个成员变量赋值的。这时候我们是否可以说,KVC永远是对带下划线的成员变量赋值的呢?那倒也未必,我们来继续看,假如此时给HMPerson删掉“_name”,只留“name”,又会是怎样。
        • 此时发现,用KVC赋值的就是这个不带下划线的成员变量(即name)了。
          因此,我们可以总结出,KVC赋值和取值的一套顺序:
          1. 用KVC取值或赋值时,会优先找这个属性对应的getter或setter方法来对这个属性赋值
          2. 如果找不到,则会查找带下划线的属性,如果找到则赋值
          3. 如果依然找不到,则会查找不带下划线的属性,如果找到则赋值
          4. 如果还是找不到,则报错(可以让它不报错,后文会详述)
            **疑问解密2:复合路径

          **
          setValue:属性值 forKeyPath:属性路径 valueForKeyPath:属性名

          复制代码

          后面带Path的跟之前我们用的KVC有什么不同呢?我们来研究研究!
          假设此时有一个Dog类,而Person类里也有个属性是Dog类型的,叫pet,如图

        • 如果此时实例化Person对象,要用KVC操作pet属性里的nickName属性就不太方便,只能先取出pet属性指向的Dog对象,再来操作nickName属性,如下:
        • 而带Path的方法,就是用来简化这种操作的,我们看
        • 因此,也就是说,如果需要操作访问一些“属性里的属性”时,就用带Path的方法来操作。
          ** 疑问解密
          3:

          **
          如果用
          KVC赋值时,某一个
          Key,类中没有会怎样?

          例如:我们的
          HMPerson类现在没有
          salary属性。

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

          **
          KVC是一套方便我们用字符串来操作对象的机制,可以使得操作对象时跟操作字典一样的灵活。在字典转模型的领域中应用起来极为方便,并且
          KVC可以轻松的帮我们突破访问限制的一些问题,直接访问到私有成员。

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

Objective-C KVC使用,包你看懂会用的相关文章

Gym 101490K Safe Racing (dp转换, 超超超级详细,包你看懂)

题意:给你一个长为L的圆形跑道,让你放置警示牌,相邻两个警示牌相隔距离不能超过S,让你求有多少种方案数放置.数据L,S都是1e6. 来个例子:L = 13, S = 5.一个圈表示长度为1. 思路:因为是一个圈,我们必须得判断最后一个牌子和第一个牌子的相距距离,所以如果我们规定了第一个放在那,最后一个放在那,这道题就简单多了.比如这个. 第一步思考: 1 当我们第一个放在1号位子时,我们最后一个能放的位置有12,13,14,15,16. 2 当我们第一个放在2号位子时,我们最后一个能放的位置有1

《大话西游》20年后重映(附影评:《大话西游》你真的看懂了吗?)

2014-10-25 02:43:24 来源: 北京日报(北京) 本报讯 (记者 周南焱)"电影里的台词差点儿都能背,但在影院里再看还是会笑.看到最后紫霞仙子死的时候.还是忍不住落泪! "昨天下午,经典老片<大话西游>在海航活力天宝影城又一次上映,一位重温影片的观众如是说.还有观众反映,用如今的电影技术水准来看,<大话西游>确实有点老土,但从内容来看还是那么亲切. 周星驰主演的<大话西游>20年前公映,当时票房大败. 但谁也没想到,该片通过盗版光碟和

你的计算机也可以看懂世界(一)——十分钟跑起卷积神经网络(Windows+CPU)

学习.使用卷积神经网络已经挺久了,期间一直在基于贾扬清大神的Caffe框架来研究别人的模型,抑或是在无聊的时候以近似于算命一样的方式,眼睛微闭,摇头晃脑,口中不时漏出几个音节,半晌便DIY出一个自认为改进颇多的模型,然后去跑一下,当然结果是非常惨淡的(要不然我就直接发论文了哪有这么闲还来写博客...),从这个过程中,我深刻地体会到了"前人栽树后人乘凉"这句话的正确性,虽然贾大神这个前人也不比我等大上几岁.今天听说贾大神宣布了最新的可以在移动设备上进行训练和测试的Caffe框架,心想我知

只有程序员可以看懂的笑话 大全集(2)

1.程序猿最烦两件事,第一件事是别人要他给自己的代码写文档,第二件呢?是别人的程序没有留下文档. 2.程序猿的读书历程:x 语言入门 -> x 语言应用实践 -> x 语言高阶编程 -> x 语言的科学与艺术 -> 编程之美 -> 编程之道 -> 编程之禅-> 颈椎病康复指南. 3.还没上大学的时候,高三暑假,跑到家那边的图书城想买传说中的C++的书,然后看到一本C#,我一看,嘿,这个++还写得挺艺术的,重叠起来了,于是把C#买了回来-- 4.问:程序猿最讨厌康熙

看懂redis

[教你看懂redis配置 – 简介] 我们可以在启动redis-server时指定应该加载的配置文件,方法如下: 复制代码 代码如下: $ ./redis-server /path/to/redis.conf 接下来,我们就来讲解下redis配置文件的各个配置项的含义,注意,本文是基于redis-2.8.4版本进行讲解的. redis官方提供的redis.conf文件,足有700+行,其中100多行为有效配置行,另外的600多行为注释说明. 在配置文件的开头部分,首先明确了一些度量单位: # 1

只有程序员可以看懂的笑话 大全集(1)

宪法顶个球!中国的法律都是.txt文件,不是.exe文件. 程序员:三年前,当我写下这个的时候,只有上帝和我能够看懂. 现在,只有 上帝能看懂了. 同事说,他在写i++的时候总觉的自己写的是 我艹.........有木有同感??? ? 程序员,年二十有二,始从文,连考而不中. 遂习武,练武场上发一矢,中鼓 吏,逐之出. 改学IT,自撰一函数,用之,堆栈溢出. <桃花庵--程序员版>写字楼里写字间,写字间中程序员: 程序人员写程序, 又将程序换酒钱: 酒醒只在屏前坐,酒醉还来屏下眠: 酒醉酒醒日

看懂Gradle脚本(2)- Groovy语言的闭包语法

本篇文章讨论下面这一小段Gradle脚本: repositories { mavenCentral() } 闭包字面量 闭包字面量看起来像Java里的代码块:用一对儿花括号包起来.前面讨论过,方法调用的圆括号可以省略,补上圆括号之后,脚本看起来是这样: repositories({ // <-- mavenCentral() }) 如果闭包是方法的最后一个参数,那么闭包可以放在圆括号外面 也就是说,上面的代码写成这样也是可以的: repositories() { // <-- mavenCen

小白也能看懂的插件化DroidPlugin原理(二)-- 反射机制和Hook入门

前言:在上一篇博文<小白也能看懂的插件化DroidPlugin原理(一)-- 动态代理>中详细介绍了 DroidPlugin 原理中涉及到的动态代理模式,看完上篇博文后你就会发现原来动态代理真的非常简单,只不过就是实现一个 InvocationHandler 接口重写一下 invoke 方法而已.不错,其实很多看似 high level 的技术都并没有想象中的那么晦涩难懂,只要你肯下定决心去了解它,去认识它,去学习它你就会发现,原来都是可以学得懂的.本篇博文将介绍 DroidPlugin 框架

【 全干货 】5 分钟带你看懂 Docker !

欢迎大家前往腾讯云社区,获取更多腾讯海量技术实践干货哦~ 作者丨唐文广:腾讯工程师,负责无线研发部地图测试. 导语:Docker,近两年才流行起来的超轻量级虚拟机,它可以让你轻松完成持续集成.自动交付.自动部署,并且实现开发环境.测试环境.运维环境三方环境的真正同步.本文从Docker定义,作用,技术架构,安装和使用等全方位带你看懂Docker. Docker是啥? 打开翻译君输入Docker 结果显示码头工人,没错!码头工人搬运的是集装箱,那么今天要讲的Docker其操作的也是集装箱,这个集装