Object-C — KVC
1:使用kvc存取对象属性
如果要更改对象属性可以通过什么方法达到呢?
(1)通过setter和getter方法。
(2)属性。
(3)直接设置实例变量。
今天学习新的一种方法:键值编码-kvc。通过指定要访问的属性名字的字符串标识符,可以进行类的属性的读取和设置。
键值编码基本调用包括:setValue:forKey:和valueForKey。
栗子:
新建Student类,属性及成员变量:
@interface Student : NSObject
{
@public
NSString * name;
@private
NSString * hobby;
}
@property(strong,nonatomic) NSString * address;
@property(nonatomic) int age;
@end
通过setter和getter方法、属性可以设置属性:
Student * stu1 = [Student new];
stu1->name = @"haha";
NSLog(@"%@",stu1->name); stu1.address = @"street"; //属性可通过点语法设置
stu1.age = ;
NSLog(@"address:%@,age:%d",stu1.address,stu1.age);
***下边通过键值编码kvc设置***
Student * stu1 = [Student new];
[stu1 setValue:@"kvcName" forKey:@"name"];
NSLog(@"kvc设置name:%@",[stu1 valueForKey:@"name"]); [stu1 setValue:@18 forKey:@"age"]; //int基本型的需要包装成oc对象型的
NSLog(@"kvc设置age:%@",[stu1 valueForKey:@"age"]);
通过kvc也可以设置属性,甚至于private的成员变量也可以设置,Student类中有一个private的成员变量:hobby
//private的属性仍然能够通过kvc设置,所以kvc破坏了面向对象的封装思想
[stu1 setValue:@"read" forKey:@"hobby"];
NSLog(@"%@",[stu1 valueForKey:@"hobby"]);
既然都可以设置属性,那么kvc和其他的有什么区别呢?它的使用场景是什么呢?
1:
key返回NSString类型的字符串。可以单独提出来:
Student * stu1 = [Student new];
NSString * key = @"name"; //变量 灵活
//[stu1 setValue:@"kvcName" forKey:@"name"];
[stu1 setValue:@"kvcName" forKey:key];
NSLog(@"kvc设置name:%@",[stu1 valueForKey:@"name"]);
这样key相当于是一个中间变量,无疑大大增强了灵活性。
2:类似id型对象不能点语法的,那么可以通过kvc设置。如:
id obj = stu1; //id 不能通过点语法设置属性
obj.name = @"hehe"; //报错
[obj setValue:@"idName" forKey:@"name"];
NSLog(@"id设置的name:%@",[obj valueForKey:@"name"]);
2:kvc特点:键搜索顺序
kvc首先查找的是setter命名的属性,为证实,重写setter,如果setter被调用则可以证实。
以Student的name成员变量为例,写setter方法:
- (void)setName:(NSString *)newName
{
NSLog(@"kvc......");
self->name = newName;
}
如果被调用则会打印kvc......,
main函数中:
Student * stu1 = [Student new];
NSString * key = @"name";
[stu1 setValue:@"kvcName" forKey:key];
NSLog(@"kvc设置name:%@",[stu1 valueForKey:@"name"]);
打印结果:

验证了。。。。。。如果不存在getter呢?也就是说不能用属性(属性会自动生成setter和getter方法),那么则会在对象内部查找_key或key的实例变量。
以Student的hobby为例,它不是属性,用没有写setter方法,现在声明hobby和_hobby,为了验证写了一个test方法:
@interface Student : NSObject
{
@public
NSString * name;
@private
NSString * hobby;
NSString * _hobby;
}
@property(strong,nonatomic) NSString * address;
@property(nonatomic) int age; - (void)test;
test方法:
- (void)test
{
NSLog(@"_hobby = %@",self->_hobby);
NSLog(@"hobby = %@",self->hobby);
}
那么当main中hobby通过kvc设置的时候,会发生什么?
Student * stu1 = [Student new];
[stu1 setValue:@"read" forKey:@"hobby"];
[stu1 test];
按说这是给hobby设置值,打印结果:

结果_hobby上有值,这就证实kvc先查找_key。
注意:使用@property+@synthesize可以自动生成getter和setter,但是如果为其指定非标准的getter和setter,key的搜索则会出现问题。
2:键值编码的键路径
设想以下情况:添加一个Brother类,Student有一个属性是Brother对象。

@interface Student : NSObject
{
@public
NSString * name;
@private
NSString * hobby;
NSString * _hobby;
}
@property(strong,nonatomic) NSString * address;
@property(nonatomic) int age;
//添加brother属性
@property(strong,nonatomic)Brother * brother;
- (void)setName:(NSString *)newName; - (void)test;
@end
而Brother类下有一个属性broName。现在有这么一个需求:我需要通过Student给brother下的broName赋值。(不是通过brother)
那么代码似乎应该这么写:
Student * stu1 = [Student new];
Brother * bro1 = [Brother new];
stu1.brother = bro1;
[stu1 setValue:@"兄弟" forKey:@"bro1.broName"];
NSLog(@"%@",[bro1 valueForKey:@"broName"]); //崩溃
这么写代码崩溃,那该怎么写呢?使用键路径:setValue:forKeyPath:
假设a对象下有一个名为b的属性,而b中包含了名称为c的属性,如果想要从a获取(或设置)c属性的内容需要使用如下路径来描述: b.c (遇到点会解析成路径)
Student * stu1 = [Student new];
Brother * bro1 = [Brother new];
stu1.brother = bro1;
[stu1 setValue:@"兄弟" forKeyPath:@"brother.broName"];
NSLog(@"%@",[stu1 valueForKeyPath:@"brother.broName"]);
这样就可以了,上面的代码稍作修改:现在brother下有一个brother对象brotherOld属性,该怎么赋值呢?
@interface Brother : NSObject
@property(strong,nonatomic) NSString * broName;
@property(strong,nonatomic) Brother * brotherOld;
@end
这样相当于通过两层去设置值。
Student * stu1 = [Student new];
Brother * bro1 = [Brother new];
stu1.brother = bro1; Brother * bigBrother = [Brother new];
bro1.brotherOld = bigBrother;
[stu1 setValue:@"大兄弟" forKeyPath:@"brother.brotherOld.broName"];
NSLog(@"%@",[stu1 valueForKeyPath:@"brother.brotherOld.broName"]);
3:键不存在的情况(了解即可)
为一个不存在的键setValue forKey的话,会报错,比如:
[stu1 setValue:@"mei you zhe ge jian" forKey:@"notExist"]; //崩溃
可以实现setValue:forUndefinedKey:
Student下声明一个字典:NSMutableDictionary * undefinedKeysAndValues可以存到这个字典中(相当于临时容器)
Student.m文件
//以下两个方法一般不重写
-(void)setValue:(id)value forUndefinedKey:(NSString *)key
{ NSLog(@"呵呵,你所访问的键:%@不存在,你就别想把值:%@放到这个键上了,说的就跟你有这个键似的!",key,value);
//[self->undefinedKeysAndValues setObject:value forKey:key];
}
-(id)valueForUndefinedKey:(NSString *)key
{
NSLog(@"对不起,没有这样的键!");
return nil;
//return [self->undefinedKeysAndValues objectForKey:key];
}
@end
4:字典的valueForKey:
NSDictionary * dict = @{@"aaa":@"",@"bbb":@""};
//NSLog(@"%@",[dict objectForKey:@"aaa"]);
NSLog(@"%@",[dict valueForKey:@"aaa"]);
打印结果:
2015-11-06 19:40:30.445 oc-kvc-001[846:61032] 11111111
Program ended with exit code: 0
本来字典的取值是通过objectForKey,现在也能通过valueForKey取值,说明valueForKey是NSobject的方法,字典继承自NSobject
5:操作集合
如果对象的某个实例变量为NSArray,而其中存放的又是对象。

Team.h文件:
@interface Team : NSObject
@property(strong,nonatomic) NSArray * members;
@end
Student.h文件:
@interface Student : NSObject
@property(copy,nonatomic) NSString * name;
@property(nonatomic) int age;
@end
Team下有一个属性为members的数组,members数组中存放的是Student对象。
Student * s1 = [Student new];
s1.name = @"学生甲";
s1.age = ; Student * s2 = [Student new];
s2.name = @"学生乙";
s2.age = ; Student * s3 = [Student new];
s3.name = @"学生丙";
s3.age = ; Student * s4 = [Student new];
s4.name = @"学生丁";
s4.age = ; NSArray * arr = @[s1,s2,s3,s4]; //对NSArray请求一个键值,则会查询数组中的每一个对象来查找这个键,然后将这些结果重新打包为一个NSArray
id ages = [arr valueForKey:@"age"];
NSLog(@"%@",ages);
//可以取最大值、最小值、求和、平均值、个数。
id maxAge = [arr valueForKeyPath:@"@max.age"];
id minAge = [arr valueForKeyPath:@"@min.age"];
id sumAge = [arr valueForKeyPath:@"@sum.age"];
id avgAge = [arr valueForKeyPath:@"@avg.age"];
id count = [arr valueForKeyPath:@"@count"];
NSLog(@"%@,%@,%@,%@,%@",maxAge,minAge,sumAge,avgAge,count); Team * team = [Team new];
team.members = arr; maxAge = [team valueForKeyPath:@"members.@max.age"];
minAge = [team valueForKeyPath:@"members.@min.age"];
sumAge = [team valueForKeyPath:@"members.@sum.age"];
avgAge = [team valueForKeyPath:@"members.@avg.age"];
count = [team valueForKeyPath:@"members.@count"];
NSLog(@"%@,%@,%@,%@,%@",maxAge,minAge,sumAge,avgAge,count);
啊╮(╯▽╰)╭,结束。。。。。。。。
Object-C — KVC的更多相关文章
- IOS开发之KVC与KVO简述
KVC:Key-Value Coding KVO:Key-Value Observing Person.m #import <Foundation/Foundation.h> @inter ...
- ios通知-kvo
// KVC: Key Value Coding, 常见作用:给模型属性赋值 // KVO: Key Value Observing, 常用作用:监听模型属性值的改变 // // ViewCon ...
- 走进 Realm 的世界
来源:XcodeMen(郭杰) 链接:http://www.jianshu.com/p/0e248f000405 本文由我们团队的郭杰童鞋分享. Realm是什么 Realm是由Y Combinato ...
- Objective-C之KVC、KVO
1,KVC(键值编码) Key Value Coding 1.1在C#中,可以通过字符串反射来获取对象,从而对对象的属性进行读写,Object-C中有同样的实现,通过字符串(属性名词)对对象的属性进 ...
- KVC 和 KVO
KVC 键值编码 全称是Key-value coding,翻译成键值编码.它提供了一种使用字符串而不是访问器方法去访问一个对象实例变量的机制. 1.通过key(成员变量的名称)设置 ...
- 11. KVC And KVO
1. KVC And KVO 的认识 KVC/KVO是观察者模式的一种实现 KVC全称是Key-value coding,翻译成键值编码.顾名思义,在某种程度上跟map的关系匪浅.它提供了一种使用 ...
- iOS开发系列--Objective-C之KVC、KVO
概述 由于ObjC主要基于Smalltalk进行设计,因此它有很多类似于Ruby.Python的动态特性,例如动态类型.动态加载.动态绑定等.今天我们着重介绍ObjC中的键值编码(KVC).键值监听( ...
- KVC & KVO
KVC和KVO看上去又是两个挺牛的单词简写,KVC是Key-Value Coding的简写,是键值编码的意思.KVO是Key-Value Observing的简写,是键值观察的意思.那么我们能拿KV ...
- iOS - 详细理解KVC与KVO
详细理解KVC与KVO 在面试的时候,KVC与KVO有些时候还是会问到的,并且他们都是Objective C的关键概念,在这里我们先做一个简单地介绍: (一)KVC: KVC即指:NSKeyValue ...
- KVC&&&KVO
KVC 什么是KVC --->What KVC指的就是NSKeyValueCoding非正式协议. KVC是一种间接地访问对象的属性的机制. 这种间接表现在通过字符串来标识属性,而不是通过调用存 ...
随机推荐
- Linux文件虚拟机系统只读Read-only file system的快速解决方法
问题描述:上周公司的私有云(底层架构是Openstack+KVM,目前稳定性还不够好,开发团队在改进中)一个计算节点挂掉,之后恢复后发现这个计算节点的所有Linux系统都变成只读了,复制文件提示:Re ...
- Codeforces 296C Greg and Array
数据结构题.个人认为是比较好的数据结构题.题意:给定一个长度为n的数组a,然后给定m个操作序列,每个操作:l, r, x将区间[l, r]内的元素都增加a,然后有k个查询,查询形式是对于操作序列x,y ...
- IoC/DIP其实是一种管理思想
关于IoC的的概念提出来已经很多年了,其被用于一种面象对像的设计.我在这里再简单的回顾一下这个概念.我先谈技术,再说管理. 话说,我们有一个开关要控制一个灯的开和关这两个动作,最常见也是最没有技术含量 ...
- nyoj 123 士兵杀敌(四) 树状数组【单点查询+区间修改】
士兵杀敌(四) 时间限制:2000 ms | 内存限制:65535 KB 难度:5 描述 南将军麾下有百万精兵,现已知共有M个士兵,编号为1~M,每次有任务的时候,总会有一批编号连在一起人请战 ...
- FlexboxLayout 的一些基本介绍与基本用法
1什么是 Flexbox 简单来说 Flexbox 是属于web前端领域CSS的一种布局方案,是2009年W3C提出了一种新的布局方案,可以简便.完整.响应式地实现各种页面布局,并且 React Na ...
- 实践javascript美术馆的小案例,学习到的东西还是蛮多的,包括javascript编程中的预留退路、分离javascript、以及实现向后兼容等
javascript美术馆(改进2) 一.javascript编程过程中的好习惯 1.实现预留退路 js被禁掉,图片也可以显示出来,href属性带有图片路径 <script src=" ...
- 遮罩层的实现(纯js兼容版)
这个代码是我以前测试时候的代码了,主要用到的知识点是opacity和filer分别实现 “标准浏览器”和IE浏览器下的半透明,使用js的document.body.offsetwidth 和scree ...
- 利用图片延迟加载来优化页面性能(jQuery)
图片延迟加载也称懒加载,常用于页面很长,图片很多的页面,以电子商务网站居多,比如大家常上的京东,淘宝,页面以图居多,整个页面少说几百K,多则上兆,如果想一次性加载完成,不仅用户要哭了,服务器也得哭了. ...
- MFC ListControl使用方法
在原来博客中有:MF CListControl 简单功能使用 推荐文章:MFC类CtrlList用法 今天又又一次来介绍点新东西:双击击listcontrol 做出响应.当然你能够做的还有非常多,比 ...
- activity中实现Spinner绑定
(1)须要一个基本的布局文件activity_main <RelativeLayout xmlns:android="http://schemas.android.com/apk/re ...