美文网首页
iOS KVC详解

iOS KVC详解

作者: 你duck不必呀 | 来源:发表于2020-02-23 17:37 被阅读0次

关于KVC的详细介绍可以参考官方文档

键值编码(KVC)是由NSKeyValueCoding非正式协议启用的一种机制,对象采用这种机制来提供对其属性的间接访问。当对象符合键值编码时,可以通过简洁,统一的消息传递接口通过字符串参数来访问其属性.

简单使用

需要遵守NSKeyValueCoding协议,直接或者间接继承自NSObject的类苹果提供了默认实现.

  1. 使用键获取属性值

简单属性,值对象

- (nullable id)valueForKey:(NSString *)key

[person valueForKey :@"age"];

有层级(属性的属性)

- (nullable id)valueForKeyPath:(NSString *)keyPath

[person valueForKeyPath :@"address.street"];

批量读取,根据传入的一组keys,依次调用valueForKey,返回一个以keys每个key为键的字典

- (NSDictionary<NSString *, id> *)dictionaryWithValuesForKeys:(NSArray<NSString *> *)keys

[person dictionaryWithValuesForKeys:@[@"name",@"age",@"hobby"]]
  1. 使用键设置属性值

注意:设置值的时候数据类型要和原来的一致,因为编译器不会提示这个错误

- (void)setValue:(nullable id)value forKey:(NSString *)key

[person setValue:@(18) forKey:@"age"];

有层级

- (void)setValue:(nullable id)value forKeyPath:(NSString *)keyPath

[person setValue:@"Sanlitun" forKeyPath:@"address.street"];

批量设置属性,这个方法会根据传入的字典参数,依次调用每个keysetValue:方法

- (void)setValuesForKeysWithDictionary:(NSDictionary<NSString *, id> *)keyedValues

[person setValuesForKeysWithDictionary:@{@"name":@"sanhe",
                                            @"age":@(24),
                                            @"hobby":@[@"羽毛球",@"高尔夫球"]
        }];
  1. 集合类型

3.1以数组为例:

如果使用某个键值来访问一个数组(NSArray),他实际上会查询相应数组中的每个对象,然后将查询结果打包成另一个数组并返回给你。

使用valueForKey:和setValue:forKey:(或其等效键路径)的任何其他对象一样,获取或设置集合对象

NSArray *newArray = [p valueForKey:@"hobby"];
newArray = @[@"羽毛球",@"高尔夫球"];
[person setValue:newArray forKey:@"hobby"];

使用协议提供的方法mutableArrayValueForKey:

此方法的默认实现与-valueForKey:识别相同的简单访问器方法和数组访问器方法,并遵循相同的直接实例变量访问策略,但是始终返回可变的集合代理对象,而不是-valueForKey:的不可变集合

NSArray *newArray = [person mutableArrayValueForKey:@"hobby"];
newArray[1] = @"高尔夫球";
[person setValue:newArray forKey:@"hobby"];

如果有层级就用对应的keyPath方法

3.2集合操作符

对象调用valueForKeyPath:时,可以在KeyPath中嵌入一个集合操作符。集合操作符是一个小的关键字列表,前面有一个@,它指定了getter应该执行的操作,以便在返回数据之前以某种方式对数据进行操作。valueForKeyPath的默认实现由NSObject提供

1.集合运算符
@avg,@count,@max,@min平均值,计数,最大值,最小值

聚合运算符可对数组或一组属性进行操作,从而生成一个反映集合某些方面的单个值。

NSMutableArray *pArray = [NSMutableArray arrayWithCapacity:10];
...
[pArray valueForKeyPath:@"@sum.age"]

2.数组运算符
返回操作对象指定属性的集合

数组中包含nil,会引发异常

@unionOfObjects返回数组
@distinctUnionOfObjects返回数组,去重

//返回的数组里的值,为age
[pArray valueForKeyPath:@"@unionOfObjects.age"]

3.嵌套运算符

嵌套运算符对嵌套集合进行操作,其中集合本身的每个条目都包含一个集合。

@distinctUnionOfArrays返回数组,去重
@unionOfArrays,返回数组
@distinctUnionOfSets返回集合,去重

  1. 访问非对象属性

KVC默认实现了非对象属性和对象属性之间的转换,

取值时如果返回不是对象,则getter使用该值初始化一个NSNumber对象(用于标量)或NSValue对象(用于结构),然后返回该值。
类似地,默认情况setValue:forKey:下,给定特定key,如果数据类型不是对象,则设置器首先将适当的<type> Value消息发送到传入值对象以提取基础数据,然后存储该数据。

自定义结构体类型:

typedef struct{
    double longitude;
    double latitude;
}Coordinates;

设置值

Person *p = [[Person alloc]init];
Coordinates coor = {121,17};
NSValue *value = [NSValue valueWithBytes:&coor objCType:@encode(Coordinates)];
[p setValue:value forKey:@"coordinates"];

读取值

NSValue *result = [p valueForKey:@"coordinates"];
Coordinates rCoor;
[result getValue:&rCoor];
  1. nil值的设置

对象类型,设置nil值仍然可用

[p setValue:nil forKey:@"age"];
 NSLog(@"%@",[p valueForKey:@"age"]);
kvcDemo[4470:510628] (null)

非对象类型设置nil

  • 注意:非对象类型通过setValue:设置nil值, 会执行setNilValueForKey:。 此方法的默认实现引发NSInvalidArgumentException异常,但是子类可以覆盖此行为

运行时会报错

[p setValue:nil forKey:@"coordinates"];

搜索模式

获取值

valueForKey:根据传入的key从调用它的类内部执行以下过程

  1. 找访问器方法:get<Key>,<key>,is<Key>,或者_<key>如果找到了,看第五步

  2. 上一步没有找到,接下来搜索countOf<Key>objectIn<Key>AtIndex:,objectsAtIndexes:(看是不是数组)
    (1) 如果找到其中的第一个,再找到其他两个中的至少一个,则创建一个响应所有NSArray方法的集合代理对象并将其返回。否则,请继续执行步骤3。
    (2) 代理对象随后将任何NSArray接收到的一些组合的消息countOf<Key>,objectIn<Key>AtIndex:<key>AtIndexes:消息给键-值编码创建它兼容的对象。如果原始对象还实现了名称为的可选方法get<Key>:range:,则代理对象也会在适当时使用该方法。实际上,代理对象与与键值编码兼容的对象一起使用,使基础属性的行为就好像它是NSArray,即使不是。

  3. 上一步没有找到,接下来找countOf<Key>,enumeratorOf<Key>和memberOf<Key>:(看是不是集合)
    (1) 如果找到所有三个方法,请创建一个响应所有NSSet方法的集合代理对象并返回该对象。随后,此代理对象将NSSet接收到的任何消息转换为,和消息的某种组合countOf<Key>,以创建该对象的对象。实际上,代理对象与与键值编码兼容的对象一起使用,使基础属性的行为就好像它是,即使不是。 enumeratorOf<Key>memberOf<Key>:NSSet
    (2) 没找到,来到第4步

  4. 如果发现收集的访问方法没有简单的存取方法或者组,如果接收器的类方法accessInstanceVariablesDirectly返回YES,搜索名为实例变量_<key>_is<Key><key>,或者is<Key>,按照这个顺序。如果找到,请直接获取实例变量的值,然后继续执行步骤5。否则,请继续执行步骤

  5. 找到对应的属性
    (1) 如果找到是个对象,直接返回;
    (2) 如果该值是支持NSNumber支持的类型,则将其存储在NSNumber实例中并返回它;
    (3) 如果结果是NSNumber不支持的标量类型,请转换为NSValue对象并返回该对象;

  6. 如果以上都没找到,会调用- (id)valueForUndefinedKey:(NSString *)key,该方法默认引发异常;

设置值

setValue:forKey:根据key` 按照以下步骤查找

  1. 查找第一个名为set<Key>:or的访问器_set<Key>,过访问器完成设置;

  2. 如果没有找到简单的访问,如果类方法accessInstanceVariablesDirectly返回YES,寻找一个实例变量与名称类似_<key>,_is<Key>,<key>,或者is<Key>,按照这个顺序。如果找到,直接用输入值(或展开值)设置变量并完成操作;

3.在找不到访问器或实例变量后,调用setValue:forUndefinedKey:。默认情况下会引发异常,但是的子类可以提供特定行为;

验证属性

validateValue:forKey:error:键值编码协议定义了支持属性验证的方法,可以重写

验证方法认为值对象有效,并在YES不更改值或错误的情况下返回。

验证方法认为值对象无效,但选择不对其进行更改。在这种情况下,该方法返回NO错误参考并将错误参考(如果由调用者提供)设置到一个NSError指示失败原因的对象。

验证方法认为值对象无效,但创建了一个新的有效对象作为替换。在这种情况下,该方法返回,YES而错误对象保持不变。在返回之前,该方法将值引用修改为指向新值对象。进行修改时,即使值对象是可变的,该方法也总是创建一个新对象,而不是修改旧对象。

Person* person = [[Person alloc] init];
NSError* error;
NSString* name = @"John";
if (![person validateValue:&name forKey:@"name" error:&error]) {
    NSLog(@"%@",error);
}

最后:

键值编码是高效的,尤其是当您依靠默认实现来完成大部分工作时,但是它确实增加了一个间接级别,该级别比直接方法调用要慢一些。因为,KVC需要解析字符串来计算你需要的的答案,此外编译器还无法对它进行错误检查,像键路径,编译器无法判断它是否是错误的路径。
仅当您可以从键值编码中受益时才使用键值编码,或者仅让您的对象参与依赖它的Cocoa技术时,才使用键值编码。

相关文章

  • iOS开发技巧系列---详解KVC(我告诉你KVC的一切)

    iOS开发技巧系列---详解KVC(我告诉你KVC的一切) iOS开发技巧系列---详解KVC(我告诉你KVC的一切)

  • iOS 关于KVC的一些总结(转)

    原文:iOS 关于KVC的一些总结 本文参考: KVC官方文档 KVC原理剖析 iOS KVC详解 KVC 简介 ...

  • iOS 关于KVC的一些总结

    本文参考: KVC官方文档 KVC原理剖析 iOS KVC详解 KVC 简介 KVC全称是Key Value Co...

  • iOS日记15-KVC

    1.iOS开发技巧系列---详解KVC 2.漫谈 KVC 与 KVO 3.KVC/KVO原理详解及编程指南 关键点...

  • iOS Objective-C KVC 详解

    iOS Objective-C KVC 详解 1. KVC简介 KVC 全称Key Value Coding,是苹...

  • OC--KVC

    参考:iOS开发技巧系列---详解KVC(我告诉你KVC的一切)KVC原理剖析 NSObject(NSKeyVal...

  • iOS - KVO

    [toc] 参考 KVO KVC 【 iOS--KVO的实现原理与具体应用 】 【 IOS-详解KVO底层实现 】...

  • iOS KVC详解

    KVC定义 KVC(Key-value coding)键值编码,就是指iOS开发中,可以允许开发中通过Key名直接...

  • iOS KVC详解

    关于KVC的详细介绍可以参考官方文档 键值编码(KVC)是由NSKeyValueCoding非正式协议启用的一种机...

  • iOS KVC 详解

    什么是KVC? KVC(Key-value coding)键值编码,单看这个名字可能不太好理解。其实是指iOS的开...

网友评论

      本文标题:iOS KVC详解

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