IOS之——键值编码(KVC)的介绍

OC中我们通常可以通过getter 和setter 来获得和修改到对象属性的值,但是还有一种更加灵活的操作方式,KVC(key value coding);

直接上代码吧
首先我们先看一个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为例子

  1. 程序优先调用“setName:属性值“,通过setter方法完成。
  2. 如果没有 setName方法,KVC机制会搜索该类名的_name的成员变量,无论成员是在类接口部分定义,还是在类实现部分定义,也无论用哪个访问控制符修饰,这条KVC代码底层实际上就是对_name成员变量赋值。
  3. 如果既没有 setName方法,也搜索不到_name 的成员变量,KVC机制会搜索该类名的name的成员变量,无论该成员是在类借口部分定义,还是在类实现部分定义,也无论用哪个访问控制符修饰,这条KVC代码底层实际上就是name成员变量赋值。
  4. 如果以上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: ‘[<Novel 0x100206ca0> 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: ‘[<Novel 0x100206cd0> 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的基本用法就是这些了。

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值