《Objective-C基础教程》读书笔记15—键值编码

许多编程技术都基于间接机制,包括整个面向对象编程领域。键值编码也是一种间接机制,这种机制不属于Objective-C语言的特性,而是Cocoa提供的一种特性。
我们可以通过直接调用方法、属性的点表示法或设置实例变量来直接更改对象状态。键值编码是一种间接更改对象状态的方式,称其为KVC,其实现方法是使用字符串表示要更改的对象状态。
一些更加高级的Cocoa特性,比如CoreData和CocoaBindings,也在基础机制中使用了KVC功能。
1 入门项目
2 KVC简介
键/值编码中的基本调用是 -valueForKey:和-setValue:forKey:方法。你可以向对象发送消息,并传递你想要访问的属性名称的键作为参数。
我们可以通过如下方法访问对象的属性:


image.png

image.png

valueForKey:的功能非常强大,它可以找到相关属性的值并将其返回。
valueForKey:会首先查找以参数名命名(格式为-key或-isKey)的getter方法。对于以上前两个调用,valueForKey:会先寻找-name和-make方法。如果没有这样的getter方法,它将会在对象内寻找名称格式为_key或key的实例变量。
非常重要的一点:-valueForKey在Objective-C运行时中使用元数据打开对象并进入其中查找需要的信息。在C或C++语言中不能执行这种操作。通过使用KVC,没有相关getter方法也能获取对象值,不需要通过对象指针来直接访问实例变量。
对于KVC, Cocoa会自动装箱和开箱标量值。也就是说,当使用setValueForKey时,它会自动将标量值(int、float和struct)放入NSNumber或NSValue中;当使用-setValueForKey时,它自动将标量值从这些对象中取出。仅KVC具有这种自动装箱功能,常规方法调用和属性语法不具备该功能。
除了检索值外,还可以使用-setValue:forKey:方法依据名称设置值。
以上方法的工作方式与-valueForKey:相同。它先查找名称的setter方法,然后调用它并传递参数。如果不存在setter方法,它将在类中寻找名为key或_key的实例变量,然后为它赋值。
编译器和苹果公司都以下划线开头的形式保存实例变量名称,所以,你最好遵守这条规则,不要在其他地方使用下划线。
如果你想设置一个标量值,在调用-setValue:forKey:方法之前需要将它们包装起来,也就是装箱到对象中,而对于KVC的赋值方法,Cocoa会自动开箱先取标量值,再赋值。
3.键路径
表示键路径:可以在不同的变量名称之间用圆点分开。


image.png

image.png

这些键路径的深度是任意的,具体取决于对象图(object graph, 可以表示对象之间的关系)的复杂度,可以使用诸如car.interior.airconditioner.fan.velocity这样的键路径。在某种程度上,使用键路径比使用一系列嵌套方法调用更容易访问到对象。
4.整体操作
关于KVC非常棒的一点是,如果使用某个键值来访问一个NSArray数组,它实际上会查询相应数组中的每个对象,然后将查询结果打包到另一个数组中并返回给你。这种方法也同样适用于通过键路径访问的位于对象中的数组。
在KVC中,通常认为对象的NSArray具有一对多的关系。如果键路径中含有一个数组属性,则该路径的其余部分将被发送给数组中的每个对象。(第二句话后一部分的理解: NSArray数组实现valueForKeyPath:的方法是循环遍历它的内容并向每个对象发送消息。因此NSArray向每个在自身之中的对象发送了参数以剩余部分作为键路径的valueForKeyPath:消息,结果就将数组中每个对象对应的属性值放到数组中返回)。
键路径的缺点: 不幸的是,不能在键路径中索引对象的数组,比如说获取对象的数组中的第一个被包含对象的属性值。
一对一关系,一般对象的复合都是一对一关系。
4.1 休息一下
懒加载也可以称之为惰性初始化,仅在需要时才去创建它。这是编程技术的一种思想。

4.2 快速运算
键路径不仅能引用对象值,还可以引用一些运算符来进行一些运算,例如能获取一组值的平均值或返回这组值中的最小值和最大值。


image.png

image.png

注意:上述代码中的@count, 其中@符号意味着后面将进行一些运算。对编译器来说,@"blah"是一个字符串,而@interface用于声明类。此处的@count用于通知KVC机制计算键路径左侧值的对象总数。而@sum、@avg、@min、@max、@distinctUnionOfObjects等运算符将键路径分成两部分。第一部分可以看成一对多关系的键路径,另一部分可以看成任何包含一对多关系的键路径。它被当作用于关系中每个对象的键路径。(获取左侧指定的集合,对该集合中的每个对象使用右侧的键路径,然后将结果转换为一个集合。名称中的union指一组对象的并集,distince用于删除重复内容。KVC还支持多种运算符,可供自己探索,不过遗憾的是,你无法添加自己的运算符。
KVC的功能非常强大,可以非常轻松地处理集合类,似乎完全可以取代对象的存取方法和其他代码编写。但是KVC有以下两个缺点:
① KVC需要解析字符串来计算你需要的答案,因此速度比较慢。
② 编译器无法对键路径进行错误检查。当你尝试使用它时,一旦出现键路径错误,程序直接crash掉。
个人意见:一般情况下,通过对象的存取方法和其他代码实现不了相应的功能时,再考虑使用KVC。
  1. 批处理
    KVC包含两个调用, 一个可以批量获取,另一个可以批量更改。


    image.png

    image.png

    注意:集合类对象中不能包含nil值,因为nil是集合类对象的终止符号,若包含,则会引起非法参数异常程序crash。在OC中,我们一般使用[NSNull null]表示nil值。

  2. nil仍然可用
    虽然nil不可在集合类对象中使用,但仍然可在KVC赋值中使用,而对于属性标量值设置为nil程序crash的问题有办法解决。


    image.png

    image.png

    注意:如果得到了一个意外之料的键,我们可以调用超类方法。
    一般来说,除非你有某些特殊的原因,比如不想执行某个操作,否则应该总是在重写的代码中调用超类的方法。

  3. 处理未定义的键
    使用KVC,处理未定义的键,需要重写相关的方法。如果KVC机制无法找到处理方式,会退回并询问该类如何处理。默认的实现会取消操作,但是我们可以更改默认的行为。


    image.png

    image.png

    image.png

    注意:
    ① <null>为后端返回数据,或者控制台打印,<null>是一种[NSNull null]对象。所以,当服务端返回<null>,前端可用[NSNull null]来进行判断;(null) 是一个真正的nil值,所以,同样,移动端可用nil值来判断服务端端返回的(null)。
    ② 对于字典,使用KVC的赋值方法(setValue:forKey:),调用者可以直接传入nil值。而如果为字典的setObject:forKey:提供nil值,它将会给出警告信息,程序crash。其实,对于后台返回的数据或者用户输入的数据,在提交字典参数请求服务端时都必须进行非空判断,最好的办法是在程序中每一处进行非空判断,另外一种办法:可以尝试使用runtime解决。
    ③ 如果在字典中对setValue:forKey:方法传入nil值,可能会把对应键的值从字典中删除。但即使这样,在kvc中,nil值仍然可用。
    小结:
    ① KVC通过查找setter和getter方法来使用单个键设置值或者获取值。如果KVC无法找到任何方法,将直接进入对象并更改值。
    ② 键路径:它们是由点分割的键,用于在对象的网络中指定路径。也许这些键路径看起来很像访问属性,但实际上它们是两种完全不同的机制。可以将各种运算符嵌入到键路径中,以使KVC实现其他功能。
    ③ 通过重写系统方法可以定制个别行为。

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

推荐阅读更多精彩内容

  • 1.ios高性能编程 (1).内层 最小的内层平均值和峰值(2).耗电量 高效的算法和数据结构(3).初始化时...
    欧辰_OSR阅读 29,346评论 8 265
  • KVC KVC定义 KVC(Key-value coding)键值编码,就是指iOS的开发中,可以允许开发者通过K...
    暮年古稀ZC阅读 2,137评论 2 9
  • Swift1> Swift和OC的区别1.1> Swift没有地址/指针的概念1.2> 泛型1.3> 类型严谨 对...
    cosWriter阅读 11,094评论 1 32
  • 源码加翻译 #import <Foundation/NSArray.h> #import <Foundation/...
    CAICAI0阅读 1,150评论 0 50
  • 关于键值编码 键值编码(KVC)是一种由NSKeyValueCoding非正式协议提供的机制,对象采用该机制来提供...
    渐z阅读 916评论 0 0