Object-C—KVC

王朝学院·作者佚名  2016-08-27
窄屏简体版  字體: 小  |  中  |  大  |  超大  

1:使用kvc存取对象属性如果要更改对象属性可以通过什么方法达到呢?

(1)通过setter和getter方法。

(2)属性。

(3)直接设置实例变量。

今天学习新的一种方法:键值编码-kvc。通过指定要访问的属性名字的字符串标识符,可以进行类的属性的读取和设置。

键值编码基本调用包括:setValue:forKey:和valueForKey。

栗子:

新建Student类,属性及成员变量:

@interfaceStudent : NSObject

{@publicNSString*name;@PRivateNSString*hobby;

}

@property(strong,nonatomic) NSString*address;

@property(nonatomic)intage;@end

通过setter和getter方法、属性可以设置属性:

Student * stu1 = [Studentnew];

stu1->name =@"haha";

NSLog(@"%@",stu1->name);

stu1.address=@"street";//属性可通过点语法设置stu1.age =100;

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 = [Studentnew];

NSString* key =@"name";//变量 灵活//[stu1 setValue:@"kvcName" forKey:@"name"];[stu1 setValue:@"kvcName"forKey:key];

NSLog(@"kvc设置name:%@",[stu1 valueForKey:@"name"]);

这样key相当于是一个中间变量,无疑大大增强了灵活性。

2:类似id型对象不能点语法的,那么可以通过kvc设置。如:

idobj = 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 = [Studentnew];

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方法:

@interfaceStudent : NSObject

{@publicNSString*name;@privateNSString*hobby;

NSString*_hobby;

}

@property(strong,nonatomic) NSString*address;

@property(nonatomic)intage;- (void)test;

test方法:

- (void)test

{

NSLog(@"_hobby = %@",self->_hobby);

NSLog(@"hobby = %@",self->hobby);

}

那么当main中hobby通过kvc设置的时候,会发生什么?

Student * stu1 = [Studentnew];

[stu1 setValue:@"read"forKey:@"hobby"];

[stu1 test];

按说这是给hobby设置值,打印结果:

结果_hobby上有值,这就证实kvc先查找_key。

注意:使用@property+@synthesize可以自动生成getter和setter,但是如果为其指定非标准的getter和setter,key的搜索则会出现问题。

2:键值编码的键路径设想以下情况:添加一个Brother类,Student有一个属性是Brother对象。

@interfaceStudent : NSObject

{@publicNSString*name;@privateNSString*hobby;

NSString*_hobby;

}

@property(strong,nonatomic) NSString*address;

@property(nonatomic)intage;//添加brother属性@property(strong,nonatomic)Brother *

brother;- (void)setName:(NSString *)newName;- (void)test;@end

而Brother类下有一个属性broName。现在有这么一个需求:我需要通过Student给brother下的broName赋值。(不是通过brother)

那么代码似乎应该这么写:

Student * stu1 = [Studentnew];

Brother* bro1 = [Brothernew];

stu1.brother=

bro1;

[stu1 setValue:@"兄弟"forKey:@"

bro1.broName"];

NSLog(@"%@",[bro1 valueForKey:@"

broName"]); //崩溃

这么写代码崩溃,那该怎么写呢?使用键路径:setValue:forKeyPath:

假设a对象下有一个名为b的属性,而b中包含了名称为c的属性,如果想要从a获取(或设置)c属性的内容需要使用如下路径来描述: b.c (遇到点会解析成路径)

Student * stu1 = [Studentnew];

Brother* bro1 = [Brothernew];

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 = [Studentnew];

Brother* bro1 = [Brothernew];

stu1.brother=

bro1;

Brother* bigBrother = [Brothernew];

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(@"对不起,没有这样的键!");returnnil;//return [self->undefinedKeysAndValues objectForKey:key];}@end

4:字典的valueForKey:NSDictionary * dict = @{@"aaa":@"11111111",@"bbb":@"22222222222"};//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文件:

@interfaceTeam : NSObject

@property(strong,nonatomic) NSArray*members;@end

Student.h文件:

@interfaceStudent : NSObject

@property(copy,nonatomic) NSString*name;

@property(nonatomic)intage;@end

Team下有一个属性为members的数组,members数组中存放的是Student对象。

Student * s1 = [Studentnew];

s1.name=@"学生甲";

s1.age=1000;

Student* s2 = [Studentnew];

s2.name=@"学生乙";

s2.age=28;

Student* s3 = [Studentnew];

s3.name=@"学生丙";

s3.age=1100;

Student* s4 = [Studentnew];

s4.name=@"学生丁";

s4.age=1400;

NSArray* arr =@[s1,s2,s3,s4];//对NSArray请求一个键值,则会查询数组中的每一个对象来查找这个键,然后将这些结果重新打包为一个NSArrayidages = [arr valueForKey:@"age"];

NSLog(@"%@",ages);

//可以取最大值、最小值、求和、平均值、个数。idmaxAge = [arr valueForKeyPath:@"@max.age"];idminAge = [arr valueForKeyPath:@"@min.age"];idsumAge = [arr valueForKeyPath:@"@sum.age"];idavgAge = [arr valueForKeyPath:@"@avg.age"];idcount = [arr valueForKeyPath:@"@count"];

NSLog(@"%@,%@,%@,%@,%@",maxAge,minAge,sumAge,avgAge,count);

Team* team = [Teamnew];

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);

啊╮(╯▽╰)╭,结束。。。。。。。。

 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
 
© 2005- 王朝網路 版權所有 導航