关于键值编码(KVC)的介绍(ios)
2016-01-15 12:27
399 查看
OC中我们通常可以通过getter 和setter 来获得和修改到对象属性的值,但是还有一种更加灵活的操作方式,KVC(key value coding);
直接上代码吧
首先我们先看一个Novel类:
接口部分
实现部分
当我们直接使用getter 或者 setter 方法对属性操作的时候,如下:
现在我们来介绍一下KVC方式
在这里说明一下底层执行机制,以name为例子
程序优先调用“setName:属性值“,通过setter方法完成。
如果没有 setName方法,KVC机制会搜索该类名的_name的成员变量,无论成员是在类接口部分定义,还是在类实现部分定义,也无论用哪个访问控制符修饰,这条KVC代码底层实际上就是对_name成员变量赋值。
如果既没有 setName方法,也搜索不到_name 的成员变量,KVC机制会搜索该类名的name的成员变量,无论该成员是在类借口部分定义,还是在类实现部分定义,也无论用哪个访问控制符修饰,这条KVC代码底层实际上就是name成员变量赋值。
如果以上3条都没有找到,系统将会执行该对象的setValue:forUnderfinedKey方法。
下面我们来测试一下上述的2、3条
我们在Novel 中 添加两个属性,test _test
现在我们在main函数的时候,用KVC来查找
[aNovel setValue:@”value” forKey:@”test”];
NSLog(@”打印test属性:%@”,aNovel->test);
NSLog(@”打印test属性:%@”,aNovel->_test);
打印结果
从这里可以看出来KVC的搜索顺序为:
①setTest:方法 ②_name成员变量 ③name成员变量
这里我们把打印修改一下
大家猜猜输出结果。
没错 结果就是:
分析一下
首先看看第一个 valueForKey:@”test”,因为test属性和_test属性都没有setter方法。按顺序KVC开始搜索_test属性,查找到_test的值是value。
然后我们看看第二个 valueForKey:@”_test”, 同样没有setter方法。按顺序搜索 __test属性,没有,再查找 _test属性。得到值value。
main函数
看看打印结果
Terminating app due to uncaught exception ‘NSUnknownKeyException‘, reason: ‘[ setValue:forUndefinedKey:]: this class is not key value coding-compliant for the key noKey.’
程序中断 并且打印出上面的信息了。为了自行处理这个异常,我们可以在类的实现部分重写setValue:forUndefinedKey方法
同样当我们通过valueForKey 方法得到相应key的值,如果key不存在也会抛出异常的,我们可以重写valueForUndefinedKey
我们来看看nil值,如果我们通过KVC为一个存在的key赋值的时候,如果是基本类型(int 、float 、double等),如果传nil的话会不会抛出异常呢?来看看吧
看看打印结果
//抛出异常 并且 程序终端
Terminating app due to uncaught exception ‘NSInvalidArgumentException‘, reason: ‘[ setNilValueForKey]: could not set nil as the value for the key _numb.’
同样我们可以重写setNilValueForKey:
setValue:forKeyPath: 根据key路径设置属性值。
valueForKeyPath:根据key路径获取属性值。
来直接看代码
先创建一个person类
Novel类中添加一个author属性
在main函数中
大致的KVC的基本用法就是这些了。
直接上代码吧
首先我们先看一个Novel类:
接口部分
#import <Foundation/Foundation.h> //小说 @interface Novel : NSObject { @private NSString* _name; //小说的名字 int _price; //小说的价格 } //为_name _price添加getter setter方法 @property (nonatomic,copy,getter=getName) NSString* name; @property (nonatomic,getter=getPrice) int price; //打印小说信息 -(void) showInfo; @end
实现部分
#import "Novel.h" @implementation Novel @synthesize name = _name; @synthesize price = _price; -(void)showInfo{ NSLog(@"小说的名字:【%@】, 价格:【%d】",_name,_price); } @end
当我们直接使用getter 或者 setter 方法对属性操作的时候,如下:
//首先创建一个Novel 对象 Novel* aNovel = [[Novel alloc]init]; // 为 aNovel设置属性 [aNovel setName:@"鬼吹灯之九层妖塔"]; [aNovel setPrice:48]; NSLog(@"小说:【%@】,价格【%d】",[aNovel getName],[aNovel getPrice]);
现在我们来介绍一下KVC方式
[aNovel setValue:@"鬼吹灯之寻龙诀" forKey:@"name"]; [aNovel setValue:[NSNumber numberWithInt:58] forKey:@"price"]; NSLog(@"小说:【%@】,价格【%@】",[aNovel valueForKey:@"name"], [aNovel valueForKey:@"price"]);Value:[需要设置的值] forKey:[所要操作的属性];
在这里说明一下底层执行机制,以name为例子
程序优先调用“setName:属性值“,通过setter方法完成。
如果没有 setName方法,KVC机制会搜索该类名的_name的成员变量,无论成员是在类接口部分定义,还是在类实现部分定义,也无论用哪个访问控制符修饰,这条KVC代码底层实际上就是对_name成员变量赋值。
如果既没有 setName方法,也搜索不到_name 的成员变量,KVC机制会搜索该类名的name的成员变量,无论该成员是在类借口部分定义,还是在类实现部分定义,也无论用哪个访问控制符修饰,这条KVC代码底层实际上就是name成员变量赋值。
如果以上3条都没有找到,系统将会执行该对象的setValue:forUnderfinedKey方法。
下面我们来测试一下上述的2、3条
我们在Novel 中 添加两个属性,test _test
@private NSString* _name; //小说的名字 int _price; //小说的价格 @package // 添加两个test属性 NSString* test; NSString* _test;
现在我们在main函数的时候,用KVC来查找
[aNovel setValue:@”value” forKey:@”test”];
NSLog(@”打印test属性:%@”,aNovel->test);
NSLog(@”打印test属性:%@”,aNovel->_test);
打印结果
打印test属性:(null) 打印test属性:value
从这里可以看出来KVC的搜索顺序为:
①setTest:方法 ②_name成员变量 ③name成员变量
这里我们把打印修改一下
NSLog(@"打印test属性:%@",[aNovel valueForKey:@"test"]); NSLog(@"打印_test属性:%@",[aNovel valueForKey:@"_test"]);
大家猜猜输出结果。
没错 结果就是:
打印test属性:value 打印_test属性:value
分析一下
首先看看第一个 valueForKey:@”test”,因为test属性和_test属性都没有setter方法。按顺序KVC开始搜索_test属性,查找到_test的值是value。
然后我们看看第二个 valueForKey:@”_test”, 同样没有setter方法。按顺序搜索 __test属性,没有,再查找 _test属性。得到值value。
处理不存在的key
直接看看代码main函数
[aNovel setValue:@"不存在的key" forKey:@"noKey"];
看看打印结果
Terminating app due to uncaught exception ‘NSUnknownKeyException‘, reason: ‘[ setValue:forUndefinedKey:]: this class is not key value coding-compliant for the key noKey.’
程序中断 并且打印出上面的信息了。为了自行处理这个异常,我们可以在类的实现部分重写setValue:forUndefinedKey方法
//重写setValue:forUndefinedKey -(void)setValue:(id)value forUndefinedKey:(NSString *)key { NSLog(@"你尝试设置的 key :【%@】并不存在!",key); NSLog(@"你设置的value :【%@】 ",value); }
同样当我们通过valueForKey 方法得到相应key的值,如果key不存在也会抛出异常的,我们可以重写valueForUndefinedKey
//重写valueForUndefinedKey -(id)valueForUndefinedKey:(NSString*)key{ NSLog(@"你设置的key :【%@】 ",key); return nil; }
我们来看看nil值,如果我们通过KVC为一个存在的key赋值的时候,如果是基本类型(int 、float 、double等),如果传nil的话会不会抛出异常呢?来看看吧
// 在Novel.h中添加 _numb属性 int _numb;
// 在main函数中测试 [aNovel setValue:nil forKey:@"_numb"];
看看打印结果
//抛出异常 并且 程序终端
Terminating app due to uncaught exception ‘NSInvalidArgumentException‘, reason: ‘[ setNilValueForKey]: could not set nil as the value for the key _numb.’
同样我们可以重写setNilValueForKey:
-(void)setNilValueForKey:(NSString *)key{ if([key isEqualToString:@"_numb"]){ //将该price设置成0 _numb = 0; }else{ //回调父类的setNilValueForKey,默认执行 [super setNilValueForKey:key]; } }
Key 路径
KVC协议中为操作Key路径的方法如下:setValue:forKeyPath: 根据key路径设置属性值。
valueForKeyPath:根据key路径获取属性值。
来直接看代码
先创建一个person类
#import <Foundation/Foundation.h> @interface Person : NSObject { //定义两个成员变量 @public NSString* _name; int _age; } // 打印名字 和 年龄 -(void) printNameAndAge; //定义一个say方法,并不提供实现 -(void) say:(NSString*)content;
Novel类中添加一个author属性
Person* _author; //小说作者
在main函数中
[aNovel setValue:[[Person alloc]init] forKey:@"author"]; [aNovel setValue:@"天下霸唱" forKeyPath:@"author.name"]; [aNovel setValue:[NSNumber numberWithInt:43] forKeyPath:@"author.age"]; NSLog(@"作者:【%@】,年龄:【%@】",[aNovel valueForKeyPath:@"author.name"],[aNovel valueForKeyPath:@"author.age"]);
大致的KVC的基本用法就是这些了。
相关文章推荐
- iOS应用程序的生命周期
- iOS 中数据的传递
- IOS补全tableview分隔线
- Mina源码分析——IoService
- 关于ios7以后带导航的界面的坐标问题
- ios植入广告
- iOS开发路线图
- iOS开发之常用六种手势
- iOS 为CALayer添加可动画的属性(以二维码切换扫描区域为例)
- [iOS开发]Xcode自动注释插件:VVDocumenter使用和安装
- iOS文字排版(CoreText)那些事儿
- iOS:APNS推送主要代码
- (转)通过WMI获取网卡MAC地址、硬盘序列号、主板序列号、CPU ID、BIOS序列号
- iOS开发真机测试could not find developer disk image的解决
- 计算缓存文件大小并清理缓存
- ios捕获异常并发送图片,便于解决bug
- iOS 【多线程安全隐患】
- ios在应用中调起qq聊天
- iOS开发~CocoaPods使用详细说明
- iOS中.pch文件如何使用