键路径(keyPath)、键值编码(KVC)、键值观察(KVO)

键路径(keyPath)

keyPath定义
键路径(keyPath)是一个由用点作分隔符的键组成的字符串,用于指定一个连接在一起的对象性质序列。
用法:@"对象.属性"
作用:常见于KVC,KVO编程,可以通过键路径访问到属性的属性。

键值编码(KVC)

KVC定义
KVC(Key-value coding)键值编码,就是指iOS的开发中,可以允许开发者通过Key名直接【访问对象的属性】,或者给对象的【属性赋值】。而不需要调用明确的存取方法。这样就可以在运行时动态地访问和修改对象的属性。而不是在编译时确定,这也是iOS开发中的黑魔法之一。很多高级的iOS开发技巧都是基于KVC实现的。
作用:在.h文件中声明过属性的类中,使用点语法和KVC访问对象其实差别不大,二者可以任意混用。但是没有在.h文件中声明过属性的的类中,点语法无法使用,这时KVC就有优势了。
使用场景:
动态地取值和设值,
用KVC来访问和修改私有变量,
Model和字典转换,
修改一些控件的内部属性,
用KVC实现高阶消息传递,
操作集合,
实现KVO

注意点
  1. 对不存在的属性,进行kvc赋值,会抛出异常,发生崩溃。
    //kvc-不存在的nameString3
    [self.homeVc setValue:@"张三" forKeyPath:@"nameString3"];

崩溃信息打印:
*** Terminating app due to uncaught exception 'NSUnknownKeyException', reason: '[<homeController 0x7fe60e509ce0> setValue:forUndefinedKey:]: this class is not key value coding-compliant for the key nameString3.'
解决办法:

在 homeController里重写

//kvc-对不存在的nameString3赋值-默认会抛出异常,引起崩溃,重写forUndefinedKey,则不会抛出异常【可在此处进行拦截,然后重定向赋值】
-(void)setValue:(id)value forUndefinedKey:(NSString *)key{

    NSLog(@"key = %@, value = %@", key, value);

    if([key isEqualToString:@"nameString3"])
    {
          self.nameString2 = value;
          return;
    }

}

2.对不存在的属性,进行kvcf取值,会抛出异常,发生崩溃。NSLog(@"%@",[self.homeVc valueForKey:@"nameString3"]);

崩溃信息打印:
*** Terminating app due to uncaught exception 'NSUnknownKeyException', reason: '[<homeController 0x7fa549c124c0> valueForUndefinedKey:]: this class is not key value coding-compliant for the key nameString3.'

//kvc-对不存在的nameString3取值-默认会抛出异常,引起崩溃,重写valueForUndefinedKey,则不会抛出异常【可在此处进行拦截,然后重定向返回值】
- (nullable id)valueForUndefinedKey:(NSString *)key{
    
    if([key isEqualToString:@"nameString3"])
    {
        return @"不存在的nameString3";
         
    }
    
    return nil;
}
KVC赋值流程
19965398-611d608c0b64e63c.png

setValue:forKey:的默认实现是给定key和value作为参数输入,尝试把value设置给以key命名的属性。过程如下:

按序搜索set<Key>:或_set<Key>,如果找到,则使用输入参数调用并结束。
如果没有找到简单的访问器方法,并且如果类方法accessInstanceVariablesDirectly返回YES(默认为YES),则按序搜索以下实例变量: _<key>/_is<Key>/<key>/is<Key>,如果找到了则直接进行赋值并结束。
以上方法皆失败则调用setValue:forUndefinedKey:,这个方法默认抛出异常,NSObject的子类可以自定义。

KVC取值流程
19965398-14c9ed20aa531ac4.png

valueForKey:的默认实现是,给定key参数作为输入,通过下面的过程,在接收valueForKey:调用的类实例中操作。

1.按顺序搜索访问器方法get<Key> / <key> / is<Key> / _<key>。如果找到,调用该方法并且带着方法的调用结果调转到第5步执行;否则,继续下一步。

2.如果没有找到简单的访问方法,搜索其名称匹配某些模式的方法的实例。其中匹配模式包含countOf<Key>,objectIn<Key>AtIndex:(对应于NSArray定义的基本方法),和<key>AtIndexs:(对应于NSArray的方法objectsAtIndexs:)
一旦找到第一个和其他两个中的至少一个,则创建一个响应所以NSArray方法并返回该方法的集合代理对象。否则,执行第3步。代理对象随后将任何NSArray接收到的一些组合的消息。

3.如果没有找到简单的访问器方法或数组访问方法组,则寻找三个方法countOf<Key>/enumeratorOf<Key>/memberOf<Key>:,对应NSSet类的基本方法。

4.如果三个方法全找到了,则创建一个集合代理对象来响应所有的NSSet方法并返回。否则,执行第4步。
如果上面的方法都没有找到,并且接受者的类方法accessInstanceVariablesDirectly返回YES(默认YES),则按序搜索以下实例变量:_<key> / _is<Key> / <key> / is<Key>。如果找到其中之一,直接获取实例变量的值并跳转到第5步;否则执行第6步。

5.如果检索到的属性值是对象指针,则只返回结果;如果值是受NSNumber支持的标量,则将其存储在NSNumber实例中并返回;如果结果是NSNumber不支持的标量,则转换成NSValue对象并返回

6.如果以上所有的尝试都失败了,则调用valueForUndefinedKey:,这个方法默认抛出异常,NSObject的子类可以重写来自定义行为。

键值观察(KVO)

KVO定义
KVO 即 Key-Value Observing,翻译成键值观察。它是一种观察者模式的衍生。其基本思想是,对目标对象的某属性添加观察,当该属性发生变化时,通过触发观察者对象实现的KVO接口方法,来自动的通知观察者。

观察者模式是什么 一个目标对象管理所有依赖于它的观察者对象,并在它自身的状态改变时主动通知观察者对象。这个主动通知通常是通过调用各观察者对象所提供的接口方法来实现的。观察者模式较完美地将目标对象与观察者对象解耦。

作用:简单来说KVO可以通过监听key,来获得value的变化,用来在对象之间监听状态变化。KVO的定义都是对NSObject的扩展来实现的,Objective-C中有个显式的NSKeyValueObserving类别名,所以对于所有继承了NSObject的类型,都能使用KVO(一些纯Swift类和结构体是不支持KVC的,因为没有继承NSObject)。

原理

KVO的实现依赖于Runtime的强大动态能力。
即当一个类型为 ObjectA 的对象,被添加了观察后,系统会生成一个 NSKVONotifying_ObjectA 类,并将对象的isa指针指向新的类,也就是说这个对象的类型发生了变化。这个类相比较于ObjectA,会重写以下几个方法。
重写setter
重写class
重写dealloc
重写_isKVOA

参考:
kvc,kvo
https://juejin.im/post/6844903602545229831
https://juejin.im/post/6844903705729302541#heading-1
kvc
https://www.jianshu.com/p/70ba4f598b49
https://www.jianshu.com/p/1d39bc610a5b
kvc崩溃
https://blog.csdn.net/u010259906/article/details/50379254
kvo
https://www.jianshu.com/p/badf5cac0130

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

推荐阅读更多精彩内容