iOS kvc
kvc在我的脑海里用来更改属性的实例变量值。
今天,他们遇到了kvc第二次去学习它,在网上看了很多博客,这似乎不符合我的口味,为了提取一些以下的。总结自己的。
http://www.cnblogs.com/stoic/archive/2012/07/20/2601315.html
这个博主写的是一些应用实例。我比較喜欢,他说明了。怎样去代码操作;
http://blog.csdn.net/omegayy/article/details/7381301
这个博主是基本的原理。
以下是自己感觉实用的东西从两位博客中摘录的。
概述
KVC是KeyValue Coding的简称。它是一种能够直接通过字符串的名字(key)来訪问类属性的机制。而不是通过调用Setter、Getter方法訪问。
当使用KVO、Core Data、CocoaBindings、AppleScript(Mac支持)时,KVC是关键技术。
怎样使用KVC
关键方法定义在:NSKeyValueCodingprotocol
KVC支持类对象和内建基本数据类型。
获取值
valueForKey:,传入NSString属性的名字。
valueForKeyPath:,传入NSString属性的路径,xx.xx形式。
valueForUndefinedKey它的默认实现是抛出异常,能够重写这个函数做错误处理。
改动值
setValue:forKey:
setValue:forKeyPath:
setValue:forUndefinedKey:
setNilValueForKey: 当对非类对象属性设置nil时,调用。默认抛出异常。
一对多关系成员的情况
mutableArrayValueForKey:有序一对多关系成员 NSArray
mutableSetValueForKey:无序一对多关系成员 NSSet
以下是一些操作实例:
1、使用KVC
#import <Foundation/Foundation.h> @interface Student : NSObject
{
NSString *name;
}
@end
#import "Student.h" int main(int argc, const char * argv[])
{
@autoreleasepool {
Student *student = [[[Student alloc]init ]autorelease];
[student setValue:@"张三" forKey:@"name"];
NSString *name = [student valueForKey:@"name"];
NSLog(@"学生姓名:%@",name);
}
return 0;
}
2、键路径訪问属性
#import <Foundation/Foundation.h> @interface Course : NSObject
{
NSString *CourseName;
}
@end
#import "Course.h" @implementation Course @end
#import <Foundation/Foundation.h>
@class Course;
@interface Student : NSObject
{
NSString *name;
Course *course;
}
@end
#import "Student.h"
#import "Course.h" int main(int argc, const char * argv[])
{
@autoreleasepool {
Student *student = [[[Student alloc]init ]autorelease];
[student setValue:@"张三" forKey:@"name"];
NSString *name = [student valueForKey:@"name"];
NSLog(@"学生姓名:%@",name); Course *course = [[[Course alloc]init] autorelease];
[course setValue:@"语文课" forKey:@"CourseName"];
[student setValue:course forKey:@"course"];
NSString *courseName = [student valueForKeyPath:@"course.CourseName"];
NSLog(@"课程名称:%@", courseName); //也能够这样存值
[student setValue:@"数学课" forKeyPath:@"course.CourseName"];
courseName = [student valueForKeyPath:@"course.CourseName"];
NSLog(@"课程名称:%@", courseName); }
return 0;
}
3、自己主动封装基本数据类型
#import <Foundation/Foundation.h>
@class Course;
@interface Student : NSObject
{
NSString *name;
Course *course;
NSInteger point;
}
@end
#import "Student.h"
#import "Course.h" int main(int argc, const char * argv[])
{
@autoreleasepool {
Student *student = [[[Student alloc]init ]autorelease];
[student setValue:@"张三" forKey:@"name"];
NSString *name = [student valueForKey:@"name"];
NSLog(@"学生姓名:%@",name); Course *course = [[[Course alloc]init] autorelease];
[course setValue:@"语文课" forKey:@"CourseName"];
[student setValue:course forKey:@"course"];
NSString *courseName = [student valueForKeyPath:@"course.CourseName"];
NSLog(@"课程名称:%@", courseName); //也能够这样存值
[student setValue:@"数学课" forKeyPath:@"course.CourseName"];
courseName = [student valueForKeyPath:@"course.CourseName"];
NSLog(@"课程名称:%@", courseName); [student setValue:@"88" forKeyPath:@"point"];
NSString *point = [student valueForKey:@"point"];
NSLog(@"分数:%@", point); }
return 0;
}
4、操作集合
#import <Foundation/Foundation.h>
@class Course;
@interface Student : NSObject
{
NSString *name;
Course *course;
NSInteger point;
NSArray *otherStudent;
}
@end
#import "Student.h"
#import "Course.h" int main(int argc, const char * argv[])
{
@autoreleasepool {
Student *student = [[[Student alloc]init ]autorelease];
[student setValue:@"张三" forKey:@"name"];
NSString *name = [student valueForKey:@"name"];
NSLog(@"学生姓名:%@",name); [student setValue:@"88" forKey:@"point"];
NSString *point = [student valueForKey:@"point"];
NSLog(@"分数:%@", point); Student *student1 = [[[Student alloc]init]autorelease];
Student *student2 = [[[Student alloc]init]autorelease];
Student *student3 = [[[Student alloc]init]autorelease];
[student1 setValue:@"65" forKey:@"point"];
[student2 setValue:@"77" forKey:@"point"];
[student3 setValue:@"99" forKey:@"point"];
NSArray *array = [NSArray arrayWithObjects:student1,student2,student3,nil];
[student setValue:array forKey:@"otherStudent"];
NSLog(@"其它学生的成绩%@", [student valueForKeyPath:@"otherStudent.point"]);
NSLog(@"共%@个学生", [student valueForKeyPath:@"otherStudent.@count"]);
NSLog(@"最高成绩:%@", [student valueForKeyPath:@"otherStudent.@max.point"]);
NSLog(@"最低成绩:%@", [student valueForKeyPath:@"otherStudent.@min.point"]);
NSLog(@"平均成绩:%@", [student valueForKeyPath:@"otherStudent.@avg.point"]);
}
return 0;
}
KVC的实现细节:
搜索Setter、Getter方法
这一部分比較重要,能让你了解到KVC调用之后。究竟是如何获取和设置类成员值的。
搜索简单的成员
如:基本类型成员。单个对象类型成员:NSInteger。NSString*成员。
a. setValue:forKey的搜索方式:
1. 首先查找设置改属性的setter方法
假设成员用@property,@synthsize处理。由于@synthsize告诉编译器自己主动生成setter:格式的setter方法,所以这样的情况下会直接搜索到。
注意:setting方法是泛指 ,指为属性赋值的方法。
2. 上面的setter方法没有找到,假设类方法accessInstanceVariablesDirectly(该方法会返回是否直接訪问没有生成成訪问器的变量)返回YES(注:这是NSKeyValueCodingCatogery中实现的类方法,默认实现为返回YES)。
那么按_name,_isname,name。is
name的顺序搜索成员名。(设变量名字为name)
3. 假设找到设置成员的值。假设没有调用setValue:forUndefinedKey:。
b. valueForKey:的搜索方式:
设变量名字为name
1. 首先按getname、name、isname的顺序查找getter方法。找到直接调用。
假设是bool、int等内建值类型,会做NSNumber的转换。
2. 上面的getter没有找到。查找countOfname、objectInnameAtIndex:、nameAtIndexes格式的方法。
假设countOf<Key>和另外两个方法中的一个找到,那么就会返回一个能够响应NSArray全部方法的代理集合(collection proxy object)。
发送给这个代理集合(collection proxy object)的NSArray消息方法,就会以countOfname、objectInnameAtIndex:、nameAtIndexes这几个方法组合的形式调用。另一个可选的getname:range:方法。
3. 还没查到,那么查找countOfname、enumeratorOfname、memberOfname:格式的方法。
假设这三个方法都找到,那么就返回一个能够响应NSSet全部方法的代理集合(collection proxy object)。发送给这个代理集合(collection proxy object)的NSSet消息方法,就会以countOfname、enumeratorOfname、memberOfname:组合的形式调用。
4. 还是没查到。那么假设类方法accessInstanceVariablesDirectly返回YES。那么按_name。_isname,name,isname的顺序直接搜索成员名。
5. 再没查到,调用valueForUndefinedKey:。
2.3.2 查找有序集合成员,比方NSMutableArray
mutableArrayValueForKey:搜索方式例如以下:
1. 搜索insertObject:in<Key>AtIndex:、removeObjectFrom<Key>AtIndex:或者insert<Key>:atIndexes、remove<Key>AtIndexes:格式的方法。
假设至少一个insert方法和至少一个remove方法找到,那么相同返回一个能够响应NSMutableArray全部方法的代理集合。那么发送给这个代理集合的NSMutableArray消息方法,以insertObject:in<Key>AtIndex:、removeObjectFrom<Key>AtIndex:、insert<Key>:atIndexes、remove<Key>AtIndexes:组合的形式调用。还有两个可选实现的接口:replaceObjectIn<Key>AtIndex:withObject:、replace<Key>AtIndexes:with<Key>:。
2. 否则,搜索set<Key>:格式的方法。假设找到,那么发送给代理集合的NSMutableArray终于都会调用set<Key>:方法。
也就是说,mutableArrayValueForKey取出的代理集合改动后,用set<Key>:又一次赋值回去。这样做效率会差非常多,所以推荐实现上面的方法。
3. 否则。那么假设类方法accessInstanceVariablesDirectly返回YES,那么按_<key>,<key>的顺序直接搜索成员名。假设找到,那么发送的NSMutableArray消息方法直接转交给这个成员处理。
4. 再找不到,调用setValue:forUndefinedKey:。
NSMutableArray *mutablearray = [kvo mutableArrayValueForKey:@"array"];//kvo为自己定义的类里面放了一个array的数组通过这种方法来获取该数组的代理,并在此改动。kvo中的array值就会对应的变化;
[mutablearray removeObject:@"234"];
[mutablearray addObject:@"345"];
2.3.3 搜索无序集合成员。如:NSSet。
mutableSetValueForKey:搜索方式例如以下:
1. 搜索add<Key>Object:、remove<Key>Object:或者add<Key>:、remove<Key>:格式的方法。假设至少一个insert方法和至少一个remove方法找到,那么返回一个能够响应NSMutableSet全部方法的代理集合。
那么发送给这个代理集合的NSMutableSet消息方法,以add<Key>Object:、remove<Key>Object:、add<Key>:、remove<Key>:组合的形式调用。
还有两个可选实现的接口:intersect<Key>、set<Key>:。
2. 假设reciever是ManagedObejct。那么就不会继续搜索了。
3. 否则,搜索set<Key>:格式的方法。假设找到。那么发送给代理集合的NSMutableSet终于都会调用set<Key>:方法。也就是说,mutableSetValueForKey取出的代理集合改动后,用set<Key>:又一次赋值回去。这样做效率会差非常多,所以推荐实现上面的方法。
4. 否则,那么假设类方法accessInstanceVariablesDirectly返回YES。那么按_<key>,<key>的顺序直接搜索成员名。
假设找到。那么发送的NSMutableSet消息方法直接转交给这个成员处理。
5. 再找不到。调用setValue:forUndefinedKey:。
KVC还提供了以下的功能
2.4 值的正确性核查
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:errorString
forKey:NSLocalizedDescriptionKey];
*outError = [[[NSError alloc] initWithDomain:PERSON_ERROR_DOMAIN
code:PERSON_INVALID_NAME_CODE
userInfo:userInfoDict] autorelease];
}
return NO;
}
return YES;
}
调用核查方法:
validateValue:forKey:error:,默认实现会搜索 validate<Key>:error:格式的核查方法。找到则调用,未找到默认返回YES。
注意当中的内存管理问题。
2.5 集合操作
集合操作通过对valueForKeyPath:传递參数来使用,一定要用在集合(如:array)上。否则产生执行时刻错误。其格式例如以下:
Left keypath部分:须要操作对象路径。
Collectionoperator部分:通过@符号确定使用的集合操作。
Rightkey path部分:须要进行集合操作的属性。
2.5.1 数据操作
@avg:平均值
@count:总数
@max:最大
@min:最小
@sum:总数
用法在上面样例中可见
确保操作的属性为数字类型,否则执行时刻错误。
2.5.2 对象操作
针对数组的情况
@distinctUnionOfObjects:返回指定属性去重后的值的数组
@unionOfObjects:返回指定属性的值的数组。不去重
属性的值不能为空。否则产生异常。
2.5.3 数组操作
针对数组的数组情况
@distinctUnionOfArrays:返回指定属性去重后的值的数组
@unionOfArrays:返回指定属性的值的数组。不去重
@distinctUnionOfSets:同上。仅仅是返回值为NSSet
演示样例代码:
2.6 效率问题
相比直接訪问KVC的效率会稍低一点,所以仅仅有当你很须要它提供的可扩展性时才使用它。
以下摘录一段留言能让我们了解为什么会用kvc:
. KVO是以KVC为基础的。有些监听不使用KVC操作会监听不到。
2. 假设用到Core Data。须要使用KVC做值的存取。(否则你会发现各种各样的问题的)
主要应用场景就是与KVO和Core Data协作。
这样的统一的直接通过字符串存取ObjC中对象的成员属性的接口,能够实现由外部脚本控件程序运行或者获取程序运行信息。
通过KVC存取二进制库中的私有成员也比較有用。
事实上,平均开发者,并不需要用太多。
版权声明:本文博客原创文章,博客,未经同意,不得转载。
iOS kvc的更多相关文章
- iOS KVC详细讲解
iOS KVC详细讲解 什么是KVC? KVC即NSKeyValueCoding,就是键-值编码的意思.一个非正式的 Protocol,是一种间接访问对象的属性使用字符串来标识属性,而不是通过调用存取 ...
- iOS - KVC 键值编码
1.KVC KVC 是 Key-Value Coding 的简写,是键值编码的意思,属于 runtime 方法.Key Value Coding 是 cocoa 的一个标准组成部分,是间接给对象属性设 ...
- [iOS] KVC 和 KVO
开发iOS经常会看见KVO和KVC这两个概念,特地了解了一下. 我的新博客wossoneri.com link KVC Key Value Coding KVC是一种用间接方式访问类的属性的机制.比如 ...
- iOS:KVC和KVO
来源: 对月流 链接:http://www.jianshu.com/p/f1393d10109d 写在前面: 关于KVC和KVO各种博客多了去了,重新整理下,就当是温习一下吧,也还算是个新手,不对的 ...
- iOS KVC,KVO
链接(写得不错,着重kvc):http://www.cocoachina.com/industry/20140224/7866.html 链接:http://www.cnblogs.com/kensh ...
- iOS KVC/KVO/KVB
看了那么多博客.描述那么复杂,其实KVC很简单,没描述的那么复杂,所以写一篇简单的易于理解的博文,切入正文: 1.KVC底层是通过runtime对method和value操作 比如说如下的一行KVC ...
- iOS KVC setValuesForKeysWithDictionary的使用
Key Value Coding Key Value Coding是cocoa的一个标准组成部分,它能让我们可以通过name(key)的方式访问property, 不必调用明确的property ac ...
- iOS.KVC.setValue:forKey:
Foundation Framework 定义了 NSObject(NSKeyValueCoding), - (void)setValue:(id)value forKey:(NSString *)k ...
- iOS KVC 和 KVO 区别简单总结
KVC: key value coding,键值编码.是一种通过使用属性的名称(key)来间接访问对象属性的方法.这个方法可以不用通过 setter/getter 方法来访问对象的属性.该方法使用的实 ...
随机推荐
- python学习笔记之八:迭代器和生成器
一. 迭代器 在前面的笔记中,已经提到过迭代器(和可迭代),这里会对此进行深入讨论.只讨论一个特殊方法---__iter__,这个方法是迭代器规则的基础. 1.1 迭代器规则 迭代的意思是重复做一些事 ...
- macbook连接linuxserver后不显示matlab桌面[问题]
macbook 登录远程linuxserver.Macbook今天,系统版本号10.9.4.这是更新,打开matlab当提醒x11不存在.一个接着安装Xquarz2.7.6. matlab它可以在本地 ...
- [TroubleShooting]'trn\bak' is incorrectly formed. SQL Server cannot process this media family.
SQL Server online consultants came across an interesting scenario where one of our client was una ...
- activity点击时各种方法的区别
用到不同方法时候某些系统有不太一样的情况: public class MainActivity extends Activity { private static String TAG = " ...
- 用数据说话,外贸产品选择(中篇)-google趋势分析法
在上篇文章<用数据说话,贸B2C产品选择(上篇)-热门搜索法>中我们能搜索出来几种产品了,那我们就拿上次搜索出来的热门产品来做一个趋势分析.我们经过几个站点挑出了几种热卖产品Wedding ...
- Android DrawerLayout 抽屉
Android DrawerLayout 抽屉 DrawerLayout 在supportV4 Lib在.类似的开源slidemenu如,DrawerLayout父类ViewGroup,自定义组件基本 ...
- Axuer 网页
http://www.webppd.com/axure/
- ubuntu 12.04安装经典的Gnome桌面
这次介绍的是如何在ubuntu 12.04 中安装经典的 GNOME桌面,默认的 Ubuntu 12.04 默认unity桌面,一些用户不喜欢 Unity 桌面,所以想找回昔日的经典Gnome桌面. ...
- logback与Spring、SpringMVC结合使用教程(转) logback good
摘要:本文主要介绍了如何在spring.springMVC中使用logback 一.logback与Spirng结合使用 1.maven添加引用: <dependency> <gro ...
- BeagleBone Black 板第三课:Debian7.5系统安装和远程控制BBB板
BBB板第三课:Debian7.5系统安装和远程控制BBB板 由于BBB板系统是Debian 7.4.据说使用Debian系统能够实现非常多BBB板的无缝连接.能够更好的学习和控制BBB板,所以就决定 ...