除了一般的赋值和取值的方法,我们还可以用Key-Value-Coding(KVC)键值编码来访问你要存取的类的属性。 如何使用KVC存取对象属性呢?看个示例 1、使用KVC 定义一个Student类,继承于NSObject。 .h文件
#import <Foundation/Foundation.h>@interface Student : NSObject{ NSString *name;}@end
.m文件
#import "Student.h"@implementation Student@end
.m文件也没有实现。name属性没有加property,原来的访问方法就访问不了name属性了。怎么办呢?用kvc就可以了
#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;}
打印结果: 2012-07-20 15:04:09.920 objectiveC[1977:403] 学生姓名:张三 张三 这个值存进去了,通过valueForKey取出来了。 如果存的时候key和类属性的名称不一致会怎么样呢? 代码改成 [student setValue:@"张三" forKey:@"name1"]; 运行,程序崩溃 ,打印: 2012-07-20 15:09:40.432 objectiveC[2069:403] *** Terminating app due to uncaught exception 'NSUnknownKeyException', reason: '[<Student 0x106f14270> setValue:forUndefinedKey:]: this class is not key value coding-compliant for the key name1.' 提示没有这个name1 这个key。 2、键路径访问属性 如果访问这个类里中的属性中的属性呢?那就用到了键路径 关键字:键路径取值valueForKeyPath 键路径存值:forKeyPath 新建一个类Course,课程类,课程类有课程名称这个属性 .h文件
#import <Foundation/Foundation.h>@interface Course : NSObject{ NSString *CourseName;}@end
.m文件
#import "Course.h"@implementation Course@end
在Student中添加Course属性 ,student.h文件中代码如下:
#import <Foundation/Foundation.h>@class Course;@interface Student : NSObject{ NSString *name; Course *course;}@end
实现还是什么都没有,这里就不贴代码了 在main方法中,我们实验通过键路径访问Course中CourseName的属性
#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;}
运行打印结果: 2012-07-20 15:33:51.902 objectiveC[2415:403] 学生姓名:张三 2012-07-20 15:33:51.904 objectiveC[2415:403] 课程名称:语文课 2012-07-20 15:33:51.904 objectiveC[2415:403] 课程名称:数学课 3、自动封装基本数据类型 我们在Student类中添加分数属性 NSInteger point; .h文件
#import <Foundation/Foundation.h>@class Course;@interface Student : NSObject{ NSString *name; Course *course; NSInteger point;}@end
.m文件不改变
#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;}
打印结果: 2012-07-20 15:43:19.593 objectiveC[2533:403] 学生姓名:张三 2012-07-20 15:43:19.596 objectiveC[2533:403] 课程名称:语文课 2012-07-20 15:43:19.596 objectiveC[2533:403] 课程名称:数学课 2012-07-20 15:43:19.598 objectiveC[2533:403] 分数:88 我们用NSString*类型设置的属性值@"88",而我们的属性是NSInteger类型的,存取都没有问题。 4、操作集合 在Student类中加入数组NSArray,用来表示其他的学生。这样我们可以添加多个其他的学生,再用集合操作计算学生的分数,最高分,最低分,平均分等
#import <Foundation/Foundation.h>@class Course;@interface Student : NSObject{ NSString *name; Course *course; NSInteger point; NSArray *otherStudent;}@end
.m文件实现不变。 在main函数中添加三个学生,添加到数组中,然后求平均分,最高,最低分,学生数量
#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;}
运行打印结果 2012-07-20 16:09:17.101 objectiveC[2857:403] 学生姓名:张三 2012-07-20 16:09:17.104 objectiveC[2857:403] 分数:88 2012-07-20 16:09:17.105 objectiveC[2857:403] 其他学生的成绩( 65, 77, 99 ) 2012-07-20 16:09:17.106 objectiveC[2857:403] 共3个学生 2012-07-20 16:09:17.106 objectiveC[2857:403] 最高成绩:99 2012-07-20 16:09:17.107 objectiveC[2857:403] 最低成绩:65 2012-07-20 16:09:17.108 objectiveC[2857:403] 平均成绩:80.333333333333333333333333333333333333 还可以求总和 @sum KVO 一,概述 KVO,即:Key-Value Observing,它提供一种机制,当指定的对象的属性被修改后,则对象就会接受到通知。简单的说就是每次指定的被观察的对象的属性被修改后,KVO就会自动通知相应的观察者了。 二,使用方法 系统框架已经支持KVO,所以程序员在使用的时候非常简单。 1. 注册,指定被观察者的属性, 2. 实现回调方法 3. 移除观察 三,实例: 假设一个场景,股票的价格显示在当前屏幕上,当股票价格更改的时候,实时显示更新其价格。 1.定义DataModel,
- @interface StockData : NSObject {
- NSString * stockName;
- float price;
- }
- @end
- @implementation StockData
- @end
2.定义此model为Controller的属性,实例化它,监听它的属性,并显示在当前的View里边
- - (void)viewDidLoad
- {
- [super viewDidLoad];
-
- stockForKVO = [[StockData alloc] init];
- [stockForKVO setValue:@"searph" forKey:@"stockName"];
- [stockForKVO setValue:@"10.0" forKey:@"price"];
- [stockForKVO addObserver:self forKeyPath:@"price" options:NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOld context:NULL];
-
- myLabel = [[UILabel alloc]initWithFrame:CGRectMake(100, 100, 100, 30 )];
- myLabel.textColor = [UIColor redColor];
- myLabel.text = [stockForKVO valueForKey:@"price"];
- [self.view addSubview:myLabel];
-
- UIButton * b = [UIButton buttonWithType:UIButtonTypeRoundedRect];
- b.frame = CGRectMake(0, 0, 100, 30);
- [b addTarget:self action:@selector(buttonAction) forControlEvents:UIControlEventTouchUpInside];
- [self.view addSubview:b];
-
- }
3.当点击button的时候,调用buttonAction方法,修改对象的属性
- -(void) buttonAction
- {
- [stockForKVO setValue:@"20.0" forKey:@"price"];
- }
4. 实现回调方法
- -(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
- {
- if([keyPath isEqualToString:@"price"])
- {
- myLabel.text = [stockForKVO valueForKey:@"price"];
- }
- }
5.增加观察与取消观察是成对出现的,所以需要在最后的时候,移除观察者
- - (void)dealloc
- {
- [super dealloc];
- [stockForKVO removeObserver:self forKeyPath:@"price"];
- [stockForKVO release];
- }
四,小结 KVO这种编码方式使用起来很简单,很适用与datamodel修改后,引发的UIVIew的变化这种情况,就像上边的例子那样,当更改属性的值后,监听对象会立即得到通知。 |