美文网首页
iOS键值编码KVC

iOS键值编码KVC

作者: 帅狗黑皮668 | 来源:发表于2018-06-19 12:08 被阅读0次

关于KVC的实现原理,网上有好多相关的文章,大同小异,感觉还是形成自己的语言写下来比较好,特写此文。

KVC是什么

kvc全称是(Key-value coding)键值编码,定义在NSKeyValueCoding.h文件中。平常我们通过setter、getter方法来设置和修改对象的属性,实际上KVC属于一种更加灵活的操作方式,这种方式我们可以通过Key名直接访问对象的属性,或者给对象的属性赋值。

协议方法

比较常用的四个方法

- (nullable id)valueForKey:(NSString *)key;                          //直接通过Key来取值
- (void)setValue:(nullable id)value forKey:(NSString *)key;          //通过Key来设值
- (nullable id)valueForKeyPath:(NSString *)keyPath;                  //通过KeyPath来取值
- (void)setValue:(nullable id)value forKeyPath:(NSString *)keyPath;  //通过KeyPath来设值

NSKeyValueCoding中提供了KVC通用的访问方法,分别是getter方法valueForKey:和setter方法setValue:forKey:,以及其衍生的keyPath方法,这两个方法各个类通用的。并且由KVC提供默认的实现,我们也可以自己重写对应的方法来改变实现。

使用keyPath方法

forKeyPath中可以利用.运算符, 就可以一层一层往下查找对象的属性
当然 在一般的修改一个对象的属性的时候,forKey和forKeyPath,没什么区别。如:
Person *p = [Person new];
[p setValue:@"jack" forKey:@"name"];
[p setValue:@"jack" forKeyPath:@"name"];
这两个是没有区别的。
但是若是层次结构深一点, 比如说Person里面有个Dog,Dog里有个Bone,如果给Bone里面的type赋值的时候,则可以[p setValue:@"猪骨" forKeyPath:@"dog.bone.type"]

调用顺序

基础Setter搜索模式

苹果官方文档中说的是:链接大致翻译为:

  1. 按顺序查找名为set<Key>:_set<Key>命名的setter。 如果找到,则用输入值调用它并完成。

  2. 如果没有找到简单的setter,并且类方法accessInstanceVariablesDirectly返回YES,则按照该顺序寻找名称类似于_<key>_is<Key><key><Key>的实例变量。 如果找到,直接用输入值设置变量并结束

  3. 如果找不到Setter或实例变量,调用setValue:forUndefinedKey:.并抛出异常。

基础Getter搜索模式

苹果官方文档说的是:链接大致翻译为:

  1. 按照该顺序搜索名为get<Key><key>is<Key>_<key>的第一个Getter实例。 如果找到,调用它并继续执行第5步并显示结果。 否则,请继续下一步。

  2. 如果没有找到简单的Getter方法,则在实例中搜索名称与模式countOf<Key>objectIn<Key>AtIndex:(与NSArray类定义的原始方法相对应)和<key>AtIndexes:(对应于NSArray方法objectsAtIndexes:)。
    如果找到其中的第一个和其他两个中的至少一个,则创建一个集合代理对象,该对象响应所有NSArray方法并返回该对象。否则,请继续执行步骤3。
    代理对象随后将它接收到的任何NSArray消息转换为countOf<Key>objectIn<Key>AtIndex:,和<Key> AtIndexes:消息到创建它的键值编码兼容对象的某种组合。如果原始对象也实现了一个名为get<Key>:range:的可选方法,则代理对象也会在适当的时候使用它。

  3. 如果上面的方法没有找到,那么会同时查找countOf<Key>enumeratorOf<Key>,memberOf<Key>格式的方法。如果这三个方法都找到,那么就返回一个可以响应NSSet所的方法的代理集合,和上面一样,给这个代理集合发NSSet的消息,就会以countOf<Key>enumeratorOf<Key>,memberOf<Key>组合的形式调用

  4. 如果没有发现简单getter方法,或集合存取方法组,以及接收类方法accessInstanceVariablesDirectly是返回YES的。搜索一个名为_<key>_is<Key><key>is<Key>的实例,根据他们的顺序。如果发现对应的实例,则立刻获得实例可用的值并跳转到第5步,否则,跳转到第6步。

  5. 如果取回的是一个对象指针,则直接返回这个结果。
    如果取回的是一个基础数据类型,但是这个基础数据类型是被NSNumber支持的,则存储为NSNumber并返回。
    如果取回的是一个不支持NSNumber的基础数据类型,则通过NSValue进行存储并返回。

  6. 如果所有情况都失败,则调用valueForUndefinedKey:方法并抛出异常,这是默认行为。

异常处理

处理不存在的key

在使用KVC时,如果没有找到对应的key或者keyPath,则会抛出NSUndefinedKeyException的异常,并导致程序crash,此时我们可以考虑重写setValue: forUndefinedKey:方法与valueForUndefinedKey:方法来避免这个问题。

处理nil值

如果属性的类型是基础类型(int,float,double等),如果将属性设置成nil,程序就会抛出NSInvalidArgumentException的异常,并导致Crash,此时我们可以重写setNilValueForKey:方法来处理这个问题。

属性验证

KVC提供了对key或者keyPath进行验证的方法

- (BOOL)validateValue:(inout id _Nullable * _Nonnull)ioValue forKey:(NSString *)inKey error:(out NSError **)outError;
- (BOOL)validateValue:(inout id _Nullable * _Nonnull)ioValue forKeyPath:(NSString *)inKeyPath error:(out NSError **)outError;

当开发者需要验证能不能用KVC设定某个值时,可以调用validateValue: forKey:这个方法来验证,如果这个类的开发者实现了-(BOOL)validate<Key>:error:这个方法,那么KVC就会直接调用这个方法来返回,如果没有,就直接返回YES,注意!注意!注意(重要的事情说三遍)KVC在设值时不会主动去做验证,需要开发者手动去验证。

Example

@implementation Person
- (BOOL)validateName:(id *)ioValue error:(NSError * __autoreleasing *)outError{
    NSString *name = *ioValue;
    if ([name isEqualToString:@"Lucy"]) {
        return YES;
    }
    return NO;
}


Person *add = [Person new];
    NSError *error;
    NSString *name = @"Jack";
    if (![add validateValue:&name forKey:@"name" error:&error]) {
        NSLog(@"error");
    }

KVC字典转模型

将后台json数据中的字典转模型,比较好的框架有SBJSON、JSONKit、MJExtension、YYModel等。但是一些简单的数据,我们可以自己用代码来实现转换。一般我都会写NSObjec的类扩展。实现代码如下:

- (id)initWithDict:(NSDictionary *)dict{
    if (self = [self init]) {
        [self setValuesForKeysWithDictionary:dict];
    }
    return self;
}

+ (id)modelWithDict:(NSDictionary *)dict{
    return [[self alloc] initWithDict:dict];
}

在使用的时候直接调用modelWithDict:就行了,但是有个弊端就是如果找不到对应的key值,就会报错导致Crash,此时只要在对应的Model类重写setValue:forUndefinedKey:方法即可。

相关文章

  • iOS开发--KVC

    KVC键值编码 首先我们先了解下什么是KVC:KVC:Key Value Codeing 键值编码,ios提供的一...

  • iOS 中的 KVC和KVO简介

    1. KVC 1.1 KVC介绍 KVC 是 Key Value Coding 的缩写,即键值编码。在iOS的开发...

  • 2.2 KVC和KVO详解

    image.png KVC KVC定义 KVC(Key-value coding)键值编码,就是指iOS的开发中,...

  • ios开发UI篇—Kvc简单介绍

    一、KVC简单介绍 KVC key valued coding 键值编码 KVC通过键值间接编码 补充: 与KVC...

  • iOS之KVC字典转模型的底层实现

    KVC: Key Value Coding (键值编码) 在iOS开发中,KVC是我们经常要使用的技术.那么KVC...

  • iOS 键值编码 KVC

    KVC KVC -- Key Value Coding 键值编码 键值编码的基本概念键值编码是一个用于简介访问对象...

  • iOS中KVC使用及原理解析

    什么是KVC? KVC即Key-Value Coding,意思键-值编码。iOS中键值编码机制是一种由NSKeyV...

  • OC-KVC

    KVC是什么 kvc就是Key-Value Coding(键值编码)。 键值编码是NSKeyValueCoding...

  • iOS中的KVC与KVO,NSNotification通知

    问题: 什么是键值编码KVC,键路径是什么? 什么是键值观察KVO? 键值编码KVC: 键值编码是一种在NSKey...

  • iOS键值编码KVC

    关于KVC的实现原理,网上有好多相关的文章,大同小异,感觉还是形成自己的语言写下来比较好,特写此文。 KVC是什么...

网友评论

      本文标题:iOS键值编码KVC

      本文链接:https://www.haomeiwen.com/subject/pudaeftx.html