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一般既有其优点,也存在其不足之处,不是吗?

Objective-C KVC讲解,包你看懂会用的更多相关文章

  1. 从零开始一起学习SLAM | 理解图优化,一步步带你看懂g2o代码

    首发于公众号:计算机视觉life 旗下知识星球「从零开始学习SLAM」 这可能是最清晰讲解g2o代码框架的文章 理解图优化,一步步带你看懂g2o框架 小白:师兄师兄,最近我在看SLAM的优化算法,有种 ...

  2. 小白都能看懂的tcp三次握手

    众所周知,TCP在建立连接时需要经过三次握手.许多初学者经常对这个过程感到混乱:SYN是干什么的,怎么一会儿是1一会儿是0?怎么既有大写的ACK又有小写的ack?为什么ACK在第二次握手才开始出现?初 ...

  3. 文科生也能看懂的iptables教程(转载)

    据说还是个MM, 写得很通俗易懂, 还很诙谐, 原文:http://dallascao.com/cn/iptables-tutorial-for-newbies/ 对于斗胆开始玩vps的文科生来讲,i ...

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

    众所周知,如果你想研究Deep Learning,那么比较常用的配置是Linux+GPU,不过现在很多非计算机专业的同学有时也会想采用Deep Learning方法来完成一些工作,那么Linux+GP ...

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

    前言:在上一篇博文<小白也能看懂的插件化DroidPlugin原理(一)-- 动态代理>中详细介绍了 DroidPlugin 原理中涉及到的动态代理模式,看完上篇博文后你就会发现原来动态代 ...

  6. 小白也能看懂的插件化DroidPlugin原理(三)-- 如何拦截startActivity方法

    前言:在前两篇文章中分别介绍了动态代理.反射机制和Hook机制,如果对这些还不太了解的童鞋建议先去参考一下前两篇文章.经过了前面两篇文章的铺垫,终于可以玩点真刀实弹的了,本篇将会通过 Hook 掉 s ...

  7. 让你能看懂的 JavaScript 闭包

    让你能看懂的 JavaScript 闭包 没有废话,直入主题,先看一段代码: var counter = (function() { var x = 1; return function() { re ...

  8. 一文看懂web服务器、应用服务器、web容器、反向代理服务器区别与联系

    我们知道,不同肤色的人外貌差别很大,而双胞胎的辨识很难.有意思的是Web服务器/Web容器/Web应用程序服务器/反向代理有点像四胞胎,在网络上经常一起出现.本文将带读者对这四个相似概念如何区分. 1 ...

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

    欢迎大家前往腾讯云社区,获取更多腾讯海量技术实践干货哦~ 作者丨唐文广:腾讯工程师,负责无线研发部地图测试. 导语:Docker,近两年才流行起来的超轻量级虚拟机,它可以让你轻松完成持续集成.自动交付 ...

随机推荐

  1. sqli-labs学习(less-5-less-7)

    先介绍一些函数 count(*) 返回在给定的选择中被选的行数,即结果的数目 报错了,但是union没有出结果?,只是为什么? 原来是这样,这样的话只能用报错注入了 (). 通过floor报错 and ...

  2. 2017-2018-2 20155315《网络对抗技术》Exp5 :MSF基础应用

    实验目的 学会用metasploit进行简单的攻击操作 教程 实验内容 metasploit中有六个模块分别是 渗透攻击模块(Exploit Modules) 辅助模块(Auxiliary Modul ...

  3. jQuery学习-事件绑定

    <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...

  4. windows7 64位机上配置支持GPU版(CUDA7.5)的OpenCV2.4.13操作步骤

    很久之前在windows7 32位上配置过GPU版的opencv,可参考http://blog.csdn.net/fengbingchun/article/details/9831837 Window ...

  5. 17-[JavaScript]- 内置对象 Array,String,Date,Math

    1.Array数组 <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> < ...

  6. 自动色彩均衡(ACE)快速算法

    ACE算法源自retinex算法,可以调整图像的对比度,实现人眼色彩恒常性和亮度恒常性,通过差分来计算目标点与周围像素点的相对明暗关系来校正最终像素值,有很好的增强效果.但是计算复杂度非常高,本文提出 ...

  7. js,indexOf()、lastIndexOf()

    indexOf() 方法可返回某个指定的字符串值在字符串中首次出现的位置. 提示和注释 注释:indexOf() 方法对大小写敏感! 注释:如果要检索的字符串值没有出现,则该方法返回 -1. 实例 在 ...

  8. Spring学习(十五)----- Spring AOP通知实例 – Advice

    Spring AOP(面向方面编程)框架,用于在模块化方面的横切关注点.简单得说,它只是一个拦截器拦截一些过程,例如,当一个方法执行,Spring AOP 可以劫持一个执行的方法,在方法执行之前或之后 ...

  9. Selenium2+python自动化-八种元素定位(Firebug和Firepath)

    前言    自动化只要掌握四步操作:获取元素,操作元素,获取返回结果,断言(返回结果与期望结果是否一致),最后自动出测试报告.本篇主要讲如何用firefox辅助工具进行元素定位.元素定位在这四个环节中 ...

  10. sketch 相关论文

    sketch 相关论文 Sketch Simplification We present a novel technique to simplify sketch drawings based on ...