KVC 键值编码

1、KVC --key-value-coding  键值编码。

KVC是一种存取值得键值编码形式。既然是存取值,那么如何存取就是KVC的关键,这种形式和字典的key-value类似,只是字典是数据类型,KVC是存取对象属性。

KVC的使用:

创建一个Student类,在Student.h文件中声明一个name属性。在Student.m中不做任何处理。

Student.h文件代码:

#import <Foundation/Foundation.h>


@interface Student : NSObject

{

    NSString *name;

}

@end

Student.m文件代码:

#import "Student.h"


@implementation Student


@end

上面的代码中,在.h文件中没有对name加property,.m文件中也没有实现name属性的读取,这样就不能够使用原来的方法去访问name属性了。现在想要访问就要使用KVC了。

main.m文件中使用KVC读写name属性:

#import <Foundation/Foundation.h>

#import "Student.h"


int main(int argc,constchar * argv[]) {

    @autoreleasepool {

        Student *student = [[Studentalloc]init];

        //使用KVCname属性赋值

        [student setValue:@"张三"forKey:@"name"];

        //使用KVC读取name属性

        NSString *name = [studentvalueForKey:@"name"];

        NSLog(@"name:%@", name);

        

    }

    return 0;

}

打印结果:

2017-03-27 11:03:45.161 OCdemo[887:51191] name:张三

Program ended with exit code: 0

在上面的这个简单的示例中,可以看出KVC其实就是简单的使用setValue:forKey:给对象属性赋值,再使用valueForKey:方法读取对象属性的值。

下面来看一段代码:

#import <Foundation/Foundation.h>

#import "Student.h"


int main(int argc,constchar * argv[]) {

    @autoreleasepool {

        Student *student = [[Studentalloc]init];

        //使用KVCname属性赋值

        [student setValue:@"张三"forKey:@"name"];

        //使用KVC读取name属性

        NSString *name = [studentvalueForKey:@"name"];

        NSLog(@"name:%@", name);

        

        //使用KVCname属性赋值

        [student setValue:@"张三"forKey:@"name1"];

        //使用KVC读取name属性

        NSString *name1 = [studentvalueForKey:@"name1"];

        NSLog(@"name:%@", name1);

        

    }

    return 0;

}

再次使用KVC给student对象的name1属性赋值、读取,可是Student类中并没有name1这个属性,这个时候系统就会报错:

2017-03-27 11:08:57.807 OCdemo[899:52498] name:张三

2017-03-27 11:08:57.810 OCdemo[899:52498] *** Terminating app due to uncaught exception 'NSUnknownKeyException', reason: '[<Student 0x100602a30> setValue:forUndefinedKey:]: this class is not key value coding-compliant for the key name1.'

*** First throw call stack:

(

0   CoreFoundation                      0x00007fff8ff06452 __exceptionPreprocess + 178

1   libobjc.A.dylib                     0x00007fff9cb75f7e objc_exception_throw + 48

2   CoreFoundation                      0x00007fff8ff06399 -[NSException raise] + 9

3   Foundation                          0x00007fff8a339314 -[NSObject(NSKeyValueCoding) setValue:forKey:] + 424

4   OCdemo                              0x0000000100000e14 main + 244

5   libdyld.dylib                       0x00007fff9dbff5ad start + 1

)

libc++abi.dylib: terminating with uncaught exception of type NSException

(lldb) 

错误原因打印的很清楚:

 this class is not key value coding-compliant for the key name1.

这个类没有name1这个key。所以在写key的时候一定要注意别写错或者写了没有生命的属性。


类的属性可以是很多种多样的,可以是字符串,数组,字典等类型的数据,也可以是一个类的对象。当一个类的对象作为另一个类的属性的时候,如何使用KVC读写呢?

这里先说几个方法:

键值路径读取对象属性

- (nullableid)valueForKeyPath:(NSString *)keyPath;

键值路径存值对象属性

- (void)setValue:(nullableid)value forKeyPath:(NSString *)keyPath;

上面这两个方法就是在类中使用另一个类作为属性时用来读写对象属性的属性的方法。


下面的代码就是Student类中有一个属性是Group类的一个对象,Group类中也有一个属性:groupName:

Group.h文件:

#import <Foundation/Foundation.h>


@interface Group : NSObject

{

    NSString *groupName;

}

@end

Group.m文件:

#import "Group.h"


@implementation Group


@end

Student.h文件:

#import <Foundation/Foundation.h>

@class Group;


@interface Student : NSObject

{

    NSString *name;

    Group *group;

}

@end

Student.m文件:

#import "Student.h"


@implementation Student


@end

main.m文件:

#import <Foundation/Foundation.h>

#import "Student.h"

#import "Group.h"


int main(int argc,constchar * argv[]) {

    @autoreleasepool {

        Student *student = [[Studentalloc]init];

        //使用KVCname属性赋值

        [student setValue:@"张三"forKey:@"name"];

        //使用KVC读取name属性

        NSString *name = [studentvalueForKey:@"name"];

        NSLog(@"name:%@", name);

        

        Group *group = [[Groupalloc]init];

        //使用KVCgroup对象的groupName属性赋值

        [group setValue:@"一组"forKey:@"groupName"];

        //使用KVCstudent对象的group属性赋值

        [student setValue:groupforKey:@"group"];

        //使用valueForKeyPath方法读取groupName属性的值

        NSString *groupName = [studentvalueForKeyPath:@"group.groupName"];

        NSLog(@"groupName:%@", groupName);

        

        //上面给groupName属性赋值的方式也可以这么写

        [student setValue:@"二组"forKeyPath:@"group.groupName"];

        //使用valueForKeyPath方法读取groupName属性的值

        NSString *groupName1 = [studentvalueForKeyPath:@"group.groupName"];

        NSLog(@"groupName:%@", groupName1);

    }

    return 0;

}

打印结果:

2017-03-27 11:37:49.936 OCdemo[934:62957] name:张三

2017-03-27 11:37:49.937 OCdemo[934:62957] groupName:一组

2017-03-27 11:37:49.937 OCdemo[934:62957] groupName:二组

Program ended with exit code: 0


- (void)setValue:(nullable id)value forKeyPath:(NSString *)keyPath;方法的另一种使用情况:

当类的属性是基础数据类型的时候,写入值得时候就要使用上面的键值路径的赋值方法了,但是要注意,在读取的时候使用的是:

- (nullableid)valueForKey:(NSString *)key;这个方法。


给Student类添加一个age属性,类型为NSInteger:

#import <Foundation/Foundation.h>

@class Group;


@interface Student : NSObject

{

    NSString *name;

    Group *group;

    NSInteger age;

}

@end

Student.m文件中代码不变。

在main.m文件中读写age属性:

#import <Foundation/Foundation.h>

#import "Student.h"

#import "Group.h"


int main(int argc,constchar * argv[]) {

    @autoreleasepool {

        Student *student = [[Studentalloc]init];

        //使用KVCname属性赋值

        [student setValue:@"张三"forKey:@"name"];

        //使用KVC读取name属性

        NSString *name = [studentvalueForKey:@"name"];

        NSLog(@"name:%@", name);

        

        Group *group = [[Groupalloc]init];

        //使用KVCgroup对象的groupName属性赋值

        [group setValue:@"一组"forKey:@"groupName"];

        //使用KVCstudent对象的group属性赋值

        [student setValue:groupforKey:@"group"];

        //使用valueForKeyPath方法读取groupName属性的值

        NSString *groupName = [studentvalueForKeyPath:@"group.groupName"];

        NSLog(@"groupName:%@", groupName);

        

        //上面给groupName属性赋值的方式也可以这么写

        [student setValue:@"二组"forKeyPath:@"group.groupName"];

        //使用valueForKeyPath方法读取groupName属性的值

        NSString *groupName1 = [studentvalueForKeyPath:@"group.groupName"];

        NSLog(@"groupName:%@", groupName1);

        

        //student对象的age属性赋值

        [student setValue:@"20"forKeyPath:@"age"];

        //读取age属性

        NSString *age = [studentvalueForKey:@"age"];

        NSLog(@"age:%@", age);

    }

    return 0;

}

打印结果:

2017-03-27 11:52:43.951 OCdemo[960:66589] name:张三

2017-03-27 11:52:43.952 OCdemo[960:66589] groupName:一组

2017-03-27 11:52:43.953 OCdemo[960:66589] groupName:二组

2017-03-27 11:52:43.953 OCdemo[960:66589] age:20

Program ended with exit code: 0

在上面的代码中:

        //student对象的age属性赋值

        [student setValue:@"20" forKeyPath:@"age"];

        //读取age属性

        NSString *age = [student valueForKey:@"age"];

        NSLog(@"age:%@", age);

这里使用@"20"给age属性赋值,这样在读取的时候就不会有问题,因为都是字符串了。


集合的操作:对象的属性克以是很多的类型,数组,字典这些类型的数据也是可以作为对象属性的,当数组作为属性的时候,又该如何使用KVC读写呢。

假设Student类中有一个数组类型的属性:others,现在我们要打印显示others的name。

代码示例:

Student.h文件:

#import <Foundation/Foundation.h>

@class Group;


@interface Student : NSObject

{

    NSString *name;

    Group *group;

    NSInteger age;

    NSArray *others;

}

@end


main.m文件:

#import <Foundation/Foundation.h>

#import "Student.h"

#import "Group.h"


int main(int argc,const char * argv[]) {

    @autoreleasepool {

        Student *student = [[Studentalloc]init];

        //使用KVCname属性赋值

        [student setValue:@"张三"forKey:@"name"];

        //使用KVC读取name属性

        NSString *name = [studentvalueForKey:@"name"];

        NSLog(@"name:%@", name);

        

        Group *group = [[Groupalloc]init];

        //使用KVCgroup对象的groupName属性赋值

        [group setValue:@"一组"forKey:@"groupName"];

        //使用KVCstudent对象的group属性赋值

        [student setValue:groupforKey:@"group"];

        //使用valueForKeyPath方法读取groupName属性的值

        NSString *groupName = [studentvalueForKeyPath:@"group.groupName"];

        NSLog(@"groupName:%@", groupName);

        

        //上面给groupName属性赋值的方式也可以这么写

        [student setValue:@"二组"forKeyPath:@"group.groupName"];

        //使用valueForKeyPath方法读取groupName属性的值

        NSString *groupName1 = [studentvalueForKeyPath:@"group.groupName"];

        NSLog(@"groupName:%@", groupName1);

        

        //student对象的age属性赋值

        [student setValue:@"20"forKeyPath:@"age"];

        //读取age属性

        NSString *age = [studentvalueForKey:@"age"];

        NSLog(@"age:%@", age);

        

        //创建对个对象

        Student *stu1 = [[Studentalloc]init];

        Student *stu2 = [[Studentalloc]init];

        

        //给对象的name赋值

        [stu1setValue:@"jack"forKey:@"name"];

        [stu2 setValue:@"rose"forKey:@"name"];

        

        //stu1stu2天假到数组中

        NSArray *array = [NSArrayarrayWithObjects:stu1, stu2,nil];

        

        //student对象的others属性赋值

        [student setValue:arrayforKey:@"others"];

        

        NSLog(@"其他学生的名字:%@", [student valueForKeyPath:@"others.name"]);

        

    }

    return 0;

}

打印结果:

2017-03-27 15:28:43.452 OCdemo[1185:121999] name:张三

2017-03-27 15:28:43.454 OCdemo[1185:121999] groupName:一组

2017-03-27 15:28:43.454 OCdemo[1185:121999] groupName:二组

2017-03-27 15:28:43.454 OCdemo[1185:121999] age:20

2017-03-27 15:28:43.455 OCdemo[1185:121999] 其他学生的名字:(

    jack,

    rose

)

Program ended with exit code: 0


在上面的代码中,可以看到,数组中存放的是一个student对象,然后再使用键值路径的读取形式将每个对象的名字读取出来,在放入数组中。


KVC的使用主要就是对属性的便利读写。在开发中的使用还是比较常见的。而且它是KVO(键值监听)的基础,也就是说KVO是基于KVC的一种设计。在下一篇文章中,将归纳一些KVO的使用。


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值