为什么80%的码农都做不了架构师?>>>   

KVC概述KVC是KeyValue Coding的简称,它是一种可以直接通过字符串的名字(key)来访问类属性的机制。而不是通过调用Setter、Getter方法访问。
当使用KVO、Core Data、CocoaBindings、AppleScript(Mac支持)时,KVC是关键技术。
使用KVC、KVO的优势通过规定了一组通用的Cocoa命名法则、调用规则等,实现了如下功能: 1. 使用一对高度规范化的访问方法,获取以及设置任何对象的任何属性的值。2. 通过继承一个特定的方法,并且指定希望监视的对象及希望监视的属性名称,就能在该对象的指定属性的值发生改变时,得到一个“通知”
(尽管这不是一个真正意 义上的通知),并且得到相关属性的值的变化(原先的值和改变后的新值)。3. 通过一个简单的函数调用,使一个视图对象的一个指定属性随时随地都和一个控制器对象或模型对象的一个指定属性保持同步。Book类的代码,头文件:#import <Foundation/Foundation.h>@interface Book : NSObject { NSString *name;
}@end实现文件:#import "Book.h"@implementation Book@end这个Book类太简单了,只有一个实例变量name。而且,按照以前掌握的技术,没有办法给这个变量赋值了。下面KVC登场,在main方法中给Book实例的name属性赋值并获取该属性的值:int main (int argc, const char * argv[]) { NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];Book *book=[[Book alloc] init]; [book setValue:@"《Objective C入门》" forKey:@"name"]; NSString *name=[book valueForKey:@"name"]; NSLog(@"book name: %@",name); [pool drain]; return 0;
}这里会发现ObjC的KVC很类似Java中通过反射得到类实例变量的方式。比如valueForKey方法先尝试在Book实例上找getName方法,如果找到就调用。
如果没有找到,则查找实例是否有name变量或者_name变量。如果还没找到,会抛出类似下面的异常:Terminating app due to uncaught exception ‘NSUnknownKeyException’, reason: ‘[<Book 0x10010c730> setValue:forUndefinedKey:]:
this class is not key value coding-compliant for the key name1.’下面把代码做一点修改,首先创建了个新类Author,图书的作者,头文件:#import <Cocoa/Cocoa.h>@interface Author : NSObject { NSString *name;
}@end也有个name属性,表示作者的姓名。实现文件什么也没写:#import "Author.h"@implementation Author@end然后,将author属性添加到Book类中,即每个Book实例都有一个author属性。头文件:#import <Foundation/Foundation.h>@class Author;@interface Book : NSObject { NSString *name; Author *author;
}@end实现文件还是什么都没有:#import "Book.h"@implementation Book@end在main方法中,通过kvc方式获取book的author的name属性:int main (int argc, const char * argv[]) { NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];Book *book=[[[Book alloc] init] autorelease]; [book setValue:@"《Objective C入门》" forKey:@"name"]; NSString *name=[book valueForKey:@"name"]; NSLog(@"book name: %@",name); Author *author=[[[Author alloc] init] autorelease]; [author setValue:@"Marshal Wu" forKey:@"name"]; [book setValue:author forKey:@"author"]; NSString *authorName=[book valueForKeyPath:@"author.name"]; NSLog(@"author name: %@",authorName); [pool drain]; return 0;
}可以看到,写法很类似JSP的EL表达式:${book.author.name}在ObjC的世界里叫Path,路径。当然,你也可以:[book setValue:@"zhangsan" forKeyPath:@"author.name"];通过路径设置属性。KVC还有一个很重要的特点,自动装箱拆箱功能。这在ObjC中是仅有的,其他情况下均需要使用比如NSNumber来手动拆装箱的。比如Book类头文件做了下面的增加:#import <Foundation/Foundation.h>@class Author;@interface Book : NSObject { NSString *name; Author *author; float price;
}@end实现文件还是没有动,不提了。main方法增加了对price赋值和获取值的调用,使用KVC方式:int main (int argc, const char * argv[]) { NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];Book *book=[[[Book alloc] init] autorelease]; [book setValue:@"《Objective C入门》" forKey:@"name"]; NSString *name=[book valueForKey:@"name"]; NSLog(@"book name: %@",name); Author *author=[[[Author alloc] init] autorelease]; [author setValue:@"Marshal Wu" forKey:@"name"]; [book setValue:author forKey:@"author"]; NSString *authorName=[book valueForKeyPath:@"author.name"]; NSLog(@"author name: %@",authorName); [book setValue:@"zhangsan" forKeyPath:@"author.name"]; [book setValue:@"10.4" forKey:@"price"]; NSLog(@"book price is %@",[book valueForKey:@"price"]); [pool drain]; return 0;
}可以看到给price输入的是NSString类型,但是没有问题,因为KVC方式会根据字符串自动转型为适当的数值。再看打印price属性,%@是打印对象,
而price属性是float基本型,这里KVC肯定做了自动装箱的处理,将基本型转为NSNumber对象。KVC还具备对集合的操作能力。比如,图书可以有相关图书,这是个1对多的关系。可以用集合来表示,这里用NSArray表示,在Book类的头文件中改动:#import <Foundation/Foundation.h>@class Author;@interface Book : NSObject { NSString *name; Author *author; float price; NSArray *relativeBooks;
}@end如果想得到相关图书的价格NSArray,可以使用KVC方式,见main方法:int main (int argc, const char * argv[]) { NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];Book *book=[[[Book alloc] init] autorelease]; [book setValue:@"《Objective C入门》" forKey:@"name"]; NSString *name=[book valueForKey:@"name"]; NSLog(@"book name: %@",name); Author *author=[[[Author alloc] init] autorelease]; [author setValue:@"Marshal Wu" forKey:@"name"]; [book setValue:author forKey:@"author"]; NSString *authorName=[book valueForKeyPath:@"author.name"]; NSLog(@"author name: %@",authorName); [book setValue:@"zhangsan" forKeyPath:@"author.name"]; [book setValue:@"10.4" forKey:@"price"]; NSLog(@"book price is %@",[book valueForKey:@"price"]); Book *book1=[[[Book alloc] init] autorelease]; [book1 setValue:@"5.0" forKey:@"price"]; Book *book2=[[[Book alloc] init] autorelease]; [book2 setValue:@"4.0" forKey:@"price"]; NSArray *books=[NSArray arrayWithObjects:book1,book2,nil]; [book setValue:books forKey:@"relativeBooks"]; NSLog(@"relative books price: %@",[book valueForKeyPath:@"relativeBooks.price"]); [pool drain]; return 0;
}增加的代码见黑体斜体部分。日志将打印出相关图书的价格列表:2011-05-26 19:27:57.456 ReleaseMemoDemo[10042:a0f] book name: 《Objective C入门》
2011-05-26 19:27:57.461 ReleaseMemoDemo[10042:a0f] author name: Marshal Wu
2011-05-26 19:27:57.462 ReleaseMemoDemo[10042:a0f] book price is 10.4
2011-05-26 19:27:57.463 ReleaseMemoDemo[10042:a0f] relative books price: ( 5, 4
)KVC还能对集合做运算,比如想得到相关图书的个数、相关图书的价格总和、相关图书的平均价格、价格的最大值和价格的最小值,见下面的代码:NSArray *books=[NSArray arrayWithObjects:book1,book2,nil];
[book setValue:books forKey:@"relativeBooks"];
NSLog(@"relative books price: %@",[book valueForKeyPath:@"relativeBooks.price"]);
NSLog(@"relative books count: %@",[book valueForKeyPath:@"relativeBooks.@count"]);
NSLog(@"relative books price sum: %@",[book valueForKeyPath:@"relativeBooks.@sum.price"]);
NSLog(@"relative books price avg: %@",[book valueForKeyPath:@"relativeBooks.@avg.price"]);
NSLog(@"relative books price avg: %@",[book valueForKeyPath:@"relativeBooks.@max.price"]);
NSLog(@"relative books price avg: %@",[book valueForKeyPath:@relativeBooks.@min.price]);相关日志:2011-05-26 19:45:27.786 ReleaseMemoDemo[10289:a0f] relative books price: ( 5, 4
)
2011-05-26 19:45:27.787 ReleaseMemoDemo[10289:a0f] relative books count: 2
2011-05-26 19:45:27.788 ReleaseMemoDemo[10289:a0f] relative books price sum: 9
2011-05-26 19:45:27.788 ReleaseMemoDemo[10289:a0f] relative books price avg: 4.5
2011-05-26 19:45:27.789 ReleaseMemoDemo[10289:a0f] relative books price avg: 5
2011-05-26 19:45:27.789 ReleaseMemoDemo[10289:a0f] relative books price avg: 4另外,如果想获得没有重复的价格集合,可以这样:Book *book1=[[[Book alloc] init] autorelease];
[book1 setValue:@"5.0" forKey:@"price"];Book *book2=[[[Book alloc] init] autorelease];
[book2 setValue:@"4.0" forKey:@"price"];Book *book3=[[[Book alloc] init] autorelease];
[book3 setValue:@"4.0" forKey:@"price"];NSArray *books=[NSArray arrayWithObjects:book1,book2,book3,nil];
[book setValue:books forKey:@"relativeBooks"];NSLog(@"relative books price: %@",[book valueForKeyPath:@"relativeBooks.price"]);
NSLog(@"relative books distinct price: %@",[book valueForKeyPath:@"relativeBooks.@distinctUnionOfObjects.price"]);NSLog(@"relative books count: %@",[book valueForKeyPath:@"relativeBooks.@count"]);
NSLog(@"relative books price sum: %@",[book valueForKeyPath:@"relativeBooks.@sum.price"]);
NSLog(@"relative books price avg: %@",[book valueForKeyPath:@"relativeBooks.@avg.price"]);
NSLog(@"relative books price avg: %@",[book valueForKeyPath:@"relativeBooks.@max.price"]);
NSLog(@"relative books price avg: %@",[book valueForKeyPath:@relativeBooks.@min.price]);这里增加了book3实例,它的价格和book2相同。在使用@distinctUnionOfObjects后,发现效果是消除重复的价格:011-05-26 19:55:41.123 ReleaseMemoDemo[10378:a0f] book price is 10.4
2011-05-26 19:55:41.124 ReleaseMemoDemo[10378:a0f] relative books price: ( 5, 4, 4
)
2011-05-26 19:55:41.124 ReleaseMemoDemo[10378:a0f] relative books distinct price: ( 4, 5
)KVC还可以在一个语句中为实例的多个属性赋值:Book *book4=[[Book alloc] init];
NSArray *bookProperties=[NSArray arrayWithObjects:@"name",@"price",nil];
NSDictionary *bookPropertiesDictionary=[book4 dictionaryWithValuesForKeys:bookProperties];
NSLog(@"book values: %@",bookPropertiesDictionary);NSDictionary *newBookPropertiesDictionary=[NSDictionary dictionaryWithObjectsAndKeys:@"《Objective C入门》",@"name", @"20.5",@"price",nil];
[book4 setValuesForKeysWithDictionary:newBookPropertiesDictionary];
NSLog(@"book with new values: %@",[book4 dictionaryWithValuesForKeys:bookProperties]);值的正确性核查
KVC提供属性值确认的API,它可以用来检查set的值是否正确、为不正确的值做一个替换值或者拒绝设置新值并返回错误原因。实现核查方法为如下格式:validate<Key>:error:如:
-(BOOL)validateName:(id *)ioValue error:(NSError **)outError
{// The name must not be nil, and must be at least two characters long.if ((*ioValue == nil) || ([(NSString *)*ioValue length] < 2]) {if (outError != NULL) {NSString *errorString = NSLocalizedStringFromTable(@"A Person's name must be at least two characters long", @"Person",@"validation: too short name error");NSDictionary *userInfoDict =[NSDictionary dictionaryWithObject:errorStringforKey:NSLocalizedDescriptionKey];*outError = [[[NSError alloc] initWithDomain:PERSON_ERROR_DOMAINcode:PERSON_INVALID_NAME_CODEuserInfo:userInfoDict] autorelease];}return NO;}return YES;
}调用核查方法: validateValue:forKey:error:,默认实现会搜索 validate<Key>:error:格式的核查方法,找到则调用,未找到默认返回YES。注意其中的内存管理问题。另外,还有两个比较高级的内容:nil和覆盖setNilValueForKey方法
覆盖valueForUndefinedKey方法
可自行看reference了解。

转载于:https://my.oschina.net/u/865478/blog/286503

Objective-C KVC相关推荐

  1. 【iOS 开发】Objective - C 面向对象 - 方法 | 成员变量 | 隐藏封装 | KVC | KVO | 初始化 | 多态

    一. Objective-C 方法详解 1. 方法属性 (1) OC 方法传参机制 Object-C 方法传参机制 : OC 中得参数传递都是值传递, 传入参数的是参数的副本; -- 基本类型 (值传 ...

  2. 【iOS 开发】Objective-C 运算符

    博客地址 : http://blog.csdn.net/shulianghan/article/details/41624613 参考文章 : 1.[iOS 开发]Object-C 运算符 2.[iO ...

  3. Objective C 类变量的声明

    Objective C中类变量的声明一般有两种方式: 1)instance variable 2)property方式声明 instance variable方式声明如下: @interface My ...

  4. Objective C内存管理之理解autorelease------面试题

    Objective C内存管理之理解autorelease Autorelease实际上只是把对release的调用延迟了,对于每一个Autorelease,系统只是把该Object放入了当前的Aut ...

  5. KVC(forKey,forKeyPath)

    KVC是Cocoa一个大招,非常牛逼. 利用KVC可以随意修改一个对象的属性或者成员变量(并且私有的也可以修改)  如:Person.m文件中: @implementation Person {   ...

  6. IOS中Key-Value Coding (KVC)的使用详解

    kvc,键值编码,是一个非正式的协议,它提供一种机制来间接访问对象的属性.直接访问对象是通过调用访问器的方法实现,而kvc不需要调用访问器的设置和获取方法,可以直接访问对象的属性. 下面介绍一下kvc ...

  7. KVC、KVO、通知

    http://blog.sina.com.cn/s/blog_6a049df00101apbz.html KVC(NSKeyValueCoding) "键-值-编码"是一种间接访问 ...

  8. swift_039(Swift中的KVC的使用方法)

    KVC简单介绍 KVC是OC特有的,KVC本质上是在运行时,动态向对象发送setValue:ForKey:方法,为对象的属性设置数值 因此,在使用KVC的方法之前,需要确保对象已经被正确实例化 在Sw ...

  9. Objective-C中的KVC与KVO(上)

    本文转载 李朴之先生博客 http://blog.csdn.net/pucker/article/details/7413280 Objective-C中的KVC与KVO是两种比较重要的技术,这里简要 ...

最新文章

  1. lnmp环境切换php版本,并安装相应redis扩展
  2. Java:Linux上java -jar xxx.jar命令执行jar包时出现Error: Invalid or corrupt jarfile xxx.jar解决方案...
  3. HBase Java API 创建表时一直卡住
  4. NAnt简单介绍和我第一个例子
  5. MyBatis-Plus_简介
  6. jsp中redirect和forward的区别
  7. 虚拟环境的常用命令 virtualenv命令
  8. php5.6 mysql5.5,PHP开发第一步,PHP5.6 + MySQL5.5 + Apache2.4环境搭建
  9. ArcGIS制图技巧系列(1)还原真实的植被
  10. 旅游管理系统项目java设计_基于JSP的旅游管理系统设计与实现(MyEclipse,SQL)
  11. apache服务器搭建
  12. python怎么输入正整数_python判断所输入的任意一个正整数是否为素数的两种方法...
  13. 机器学习预测股票涨跌
  14. 解决safari浏览器拦截window.open
  15. 【屏幕灯】MI电脑显示器灯条用户手册
  16. 杭电ACM 2014:青年歌手大奖赛_评委会打分
  17. 如何让你的电脑声音增大500%
  18. python wx窗体界面
  19. 求X的N次方x^n(幂)递归和非递归和pow C语言初学
  20. MySQL调优篇:单机数据库如何在高并发场景下健步如飞?

热门文章

  1. 简明python教程在线-Python简明教程
  2. c语言有参有类最小公倍数,C语言求最大公约数和最小公倍数算法
  3. mysql读写分离和组复制_数据库主从复制,读写分离,负载均衡,分库分表分别表达的什么概念?...
  4. spring中是如何解析@Profile注解的
  5. HTML锚点控制,跳转页面后定位到相应位置
  6. MAC如何查看某个端口的占用情况
  7. 《代码阅读方法与实践》阅读笔记一
  8. 一个晚上,输掉了整个世界!
  9. python无法导入pyaudio_python – pyaudio无法导入_portaudio
  10. OVS vswitchd启动(三十九)