KVC的理解

一、简介

KVC,即是指 NSKeyValueCoding,一个非正式的 Protocol,提供一种机制来间接访问对象的属性。KVO 就是基于 KVC 实现的关键技术之一。


二、相关技术


1 KVC定义了一种按名称访问对象属性的机制,支持这种访问的主要方法是:
[java]  view plain  copy
  1. - (id)valueForKey:(NSString *)key;  
  2. - (void)setValue:(id)value forKey:(NSString *)key;  
  3. - (id)valueForKeyPath:(NSString *)keyPath;  
  4. - (void)setValue:(id)value forKeyPath:(NSString *)keyPath;  
前边两个方法用到的Key较容易理解,就是要访问的属性名称对应的字符串。
后面两个方法用到的KeyPath是一个被点操作符隔开的用于访问对象的指定属性的字符串序列。

值得注意的是:访问的属性类型非oc对象时:基本数据类型封装成NSNumber对象进行赋值,机构体时封装成NSValue对象进行赋值,KVC会自动的将封装的对象转换成与之相应的数据类型;当访问的属性是oc对象时与之必须保持一致 ;或者会出现程序崩溃;
2、点语法和KVC
在实现了访问器方法的类中,使用点语法和KVC访问对象其实差别不大,二者可以任意混用。但是没有访问起方法的类中,点语法无法使用,这时KVC就有优势了。
3、键值验证
KVC提供了验证Key对应的Value是否可用的方法:
[java]  view plain  copy
  1. - (BOOL)validateValue:(inout id *)ioValue forKey:(NSString *)inKey error:(out NSError **)outError; 
需要指出的是,KVC是不会自动调用键值验证方法的,就是说我们需要手动验证。但是有些技术,比如CoreData会自动调用。
当该函数返回的结果为NO时;不可调用上述的方法进行属性访问,否则程序崩溃;当然本函数一般是我们对value数据类型不确定时才需要进行验证;

4 、集合运算符
集合运算符是一个特殊的Key Path,可以作为参数传递给valueForKeyPath:方法, 注意只能是这个方法除@count外,如果传给了valueForKey:程序崩溃。
运算符是一个以@开头的特殊字符串,格式如下图所示:
①简单集合运算符
简单集合运算符共有@avg,@count,@max,@min,@sum 5种,分别为平均值,总数,最大值,最小值,总和,目前还不支持自定义

其中 @count不需要路径直接进行访问,这也是可以用valueForKey进行访问的原因;而@avg,@max,@min,@sum 需要跟集合里面对象的某个属性进行一起使用;

假设一个数字arr中存放的是Person对象。而Persong对象中有age,name两个属性;
NSNumber  *age=[arr   valueForKeyPath:@"@count"];//返回改数组的长度
NSNumber  *age=[arr  valueForKeyPath:@"@avg.age"];//返回改数组中所有人的平均年龄
②对象运算符
比集合运算符稍微复杂,能以数组的方式返回指定的内容,一共有两种:@distinctUnionOfObjects @unionOfObjects
它们的返回值都是NSArray,区别是前者返回的元素都是唯一的,是去重以后的结果;后者返回的元素是全集,同时后则可以忽略不写。
假设一个数字arr中存放的是Person对象。而Persong对象中有age,name两个属性;用法如下:
NSArray *arrnames = [arr valueForKeyPath:@"@distinctUnionOfObjects.name"];
NSArray *arrnames = [arr valueForKeyPath:@"@unionOfObjects.name"]《==》[arr valueForKeyPath:@"name"];
前者会将的姓名去除重复的以后返回,后者直接返回所有人的姓名。
三、实现原理
1、KVC如何访问属性值
KVC再某种程度上提供了访问器的替代方案。不过访问器方法是一个很好的东西,以至于只要是有可能,KVC也尽量再访问器方法的帮助下工作。为了设置或者返回对象属性,KVC按顺序使用如下技术:
①检查是否存在-<key>、-is<key>(只针对布尔值有效)或者-get<key>的访问器方法,如果有可能,就是用这些方法返回值;
检查是否存在名为-set<key>:的方法,并使用它做设置值。对于 -get<key>和-set<key>:方法,将大写Key字符串的第一个字母,并与Cocoa的方法命名保持一致;
②如果上述方法不可用,则检查名为-_<key>、-_is<key>(只针对布尔值有效)、-_get<key>和-_set<key>:方法;
③如果没有找到访问器方法,可以尝试直接访问实例变量。实例变量可以是名为:<key>或_<key>;
④如果仍为找到,则调用valueForUndefinedKey:和setValue:forUndefinedKey:方法。这些方法的默认实现都是抛出异常,我们可以根据需要重写它们。

2、KVO的运行机制

当某个类的对象第被观察时;系统通过会调下例两个方法来调实现kvo
- (void)willChangeValueForKey:(NSString *)key 
- (void)didChangeValueForKey:(NSString *)key
1:实现set方法的
    是在set方法中的调起上面两个函数的:
2:如果没有 实现set方法的,-setValue:forKey方法会直接调用上面两个方法;
从而调起
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
而且我门不难发现在我们重写上述两个函数时,只要其中一个函数不调用它父类的该函数时kvo都将会失效;



  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值