除了:getter setter 方法,点语法, ->访问修饰符以外,咱们还能够用 KVC(Key-Value-Coding) 键值编码来操做对象。数组
那么究竟如何使用KVC操做对象的属性呢?下面我会用详细的例子来说解。app
一、KVC的简单的赋值与取值函数
赋值方法:[obj setValue:@"newValue" forKey:@"propertyName"];this
取值方法:NSString * [obj valueForKey:@"propertyName"];编码
1.1.在下面的案例中,咱们设计了一个Teacher类,他继承自NSObject,而且拥有一个名为name的字段(属性)。spa
#import <Foundation/Foundation.h> @interface Teacher : NSObject { NSString *name; } @end @implementation Teacher @end
1.2. 由于没有加@property关键字,而且没有加@public关键字,因此点语法和->访问修饰符都没法操做该字段,那么怎么办呢?设计
在下文的案例中,咱们使用KVC(Key Value Coding),将能为该字段赋值,并取出打印。code
#import "Teacher.h" int main(int argc, const char * argv[]) { @autoreleasepool { Teacher *teacher = [[Teacher alloc] init]; [teacher setValue:@"星星老师" forKey:@"name"]; NSString *name = [teacher valueForKey:@"name"]; NSLog(@"这个世界上最伟大的老师是:%@",name); } return 0; }
1.3. 那么若是 “key” 和对象的字段名称不一致会发生什么状况呢? 对象
#import "Teacher.h" int main(int argc, const char * argv[]) { @autoreleasepool { Teacher *teacher = [[Teacher alloc] init]; [teacher setValue:@"其余老师" forKey:@"otherName"]; //程序在这里崩溃将会崩溃,而且输出结果,表示该类没有名为otherName 的key //print results: *** Terminating app due to uncaught exception 'NSUnknownKeyException', reason: '[<Teacher 0x100110780> setValue:forUndefinedKey:]: this class is not key value coding-compliant for the key otherName.' } return 0; }
二、KVC键路径访问属性blog
若是访问这个类里中的属性中的属性呢?
那咱们会须要用到键路径:keyPath
键路径取值方法:[obj valueForKeyPath:@"propertyName"]
键路径赋值方法:[obj setValue:id forKeyPath:@"propertyName"]
2.1. 新建一个类Student,学生类,有name这个字段
#import <Foundation/Foundation.h> @interface Student : NSObject { NSString *studentName; } @end @implementation Student @end
2.2.在Teacher中添加Student字段:
#import <Foundation/Foundation.h> @class Student; @interface Teacher : NSObject { NSString *name; Student *student; } @end
2.3.在main方法中,咱们实验经过键路径访问对象teacher中的字段 student的studentName
#import "Teacher.h" #import "Student.h" int main(int argc, const char * argv[]) { @autoreleasepool { Teacher *teacher = [[Teacher alloc] init]; [teacher setValue:@"星星老师" forKey:@"name"]; NSString *teacherName = [teacher valueForKey:@"name"]; NSLog(@"世界上最伟大的老师是:%@",teacherName); Student *student = [[Student alloc] init]; [student setValue:@"小灰灰" forKey:@"studentName"]; [teacher setValue:student forKey:@"student"]; NSString *studentName = [teacher valueForKeyPath:@"student.studentName"]; NSLog(@"%@最漂亮的学生是:%@", teacherName, studentName); //固然,咱们也能够经过“.(点)语法"来赋值 [teacher setValue:@"大灰灰" forKeyPath:@"student.studentName"]; studentName = [teacher valueForKeyPath:@"student.studentName"]; NSLog(@"%@最可爱的学生是:%@",teacherName, studentName); /* print result is: 世界上最伟大的老师是:星星老师 星星老师最漂亮的学生是:小灰灰 星星老师最可爱的学生是:大灰灰 */ } return 0; }
三、基本数据类型的自动类型推导
3.1.咱们在Teacher 类中添加年龄字段 NSInteger age;
#import <Foundation/Foundation.h> @class Student; @interface Teacher : NSObject { NSString *name; Student *student; NSInteger age; } @end
3.2. 咱们用NSString类型设置值@"18",而age字段是NSInteger类型的,赋值取值都没有问题。
#import "Student.h" #import "Teacher.h" int main(int argc, const char * argv[]) { @autoreleasepool { Teacher *teacher = [[Teacher alloc] init]; [teacher setValue:@"星星老师" forKey:@"name"]; [teacher setValue:@"18" forKey:@"age"]; NSString *teacherName = [teacher valueForKey:@"name"]; NSString *age = [teacher valueForKey:@"age"]; NSLog(@"世界上最伟大的老师是:%@,他永远%@岁",teacherName, age); // print result is: // 世界上最伟大的老师是:星星老师,他永远18岁 } return 0; }
四、操做集合NSArray
知识点:@max,@min,@avg,@sum的使用
4.1. 在Teacher类中加入数组NSArray *students,这样咱们能够添加多个学生。
#import <Foundation/Foundation.h> @class Student; @interface Teacher : NSObject { NSString *name; //Student *student; NSInteger age; NSArray *students; } @end
4.2. 咱们再给Student类中新增score 学分
#import <Foundation/Foundation.h> @interface Student : NSObject { NSString *studentName; NSInteger score; } @end
4.2. 在main函数中添加三个学生,添加到数组中,而后求学生数量,最低分,最高分,平均分,总分
#import "Student.h" #import "Teacher.h" int main(int argc, const char * argv[]) { @autoreleasepool { Teacher *teacher = [[Teacher alloc] init]; [teacher setValue:@"星星老师" forKey:@"name"]; Student *student1 = [[Student alloc] init]; [student1 setValue:@"99" forKey:@"score"]; Student *student2 = [[Student alloc] init]; [student2 setValue:@"97" forKey:@"score"]; Student *student3 = [[Student alloc] init]; [student3 setValue:@"100" forKey:@"score"]; NSArray *array = [NSArray arrayWithObjects:student1,student2,student3,nil]; [teacher setValue:array forKey:@"students"]; NSLog(@"这个集合是%@", [teacher valueForKeyPath:@"students.score"]); NSLog(@"%@一共有%@个学生",[teacher valueForKeyPath:@"name"],[teacher valueForKeyPath:@"students.@count"]); NSLog(@"其中最高学分:%@", [teacher valueForKeyPath:@"students.@max.score"]); NSLog(@"最低学分:%@", [teacher valueForKeyPath:@"students.@min.score"]); NSLog(@"平均学分:%@", [teacher valueForKeyPath:@"students.@avg.score"]); NSLog(@"学分总和是%@",[teacher valueForKeyPath:@"students.@sum.score"]); /* print result is: 这个集合是( 99, 96, 100 ) 星星老师共3个学生 其中最高学分:100 最低学分:96 平均学分:98.666666666666666666666666666666666666 学分总和是295 */ } return 0; }
五、操做字典NSDictionary
知识点:[obj setValuesForKeysWithDictionary];
5.1. 咱们能够经过一个NSDictionary来给一个对象初始化值
#import "Student.h" #import "Teacher.h" int main(int argc, const char * argv[]) { @autoreleasepool { NSDictionary *dictStudent = @{@"studentName":@"灰灰",@"score":@100}; NSDictionary *dictTeacher = @{@"name":@"星星老师",@"age":@18,@"student":dictStudent}; Teacher *teacher = [[Teacher alloc] init]; [teacher setValuesForKeysWithDictionary:dictTeacher]; NSString *name = [teacher valueForKey:@"name"]; NSString *age = [teacher valueForKey:@"age"]; NSString *studentName = [teacher valueForKeyPath:@"student.studentName"]; NSString *score = [teacher valueForKeyPath:@"student.score"]; NSLog(@"世界上最帅的老师是:%@, 他永远%@岁",name ,age); NSLog(@"%@得了%@分",studentName,score); // print result is // 世界上最帅的老师是:星星老师, 他永远18岁 // 灰灰得了100分 } return 0; }
5.2. 可是该Dictionary 中的key值必定要与对象中的字段(属性)名称一致,数量能够少,可是不能多,不然仍然会报
“this class is not key value coding-compliant for the key otherName ” 该错误
5.3. 值的一提的是,该方法仍是有缺陷的,该方法并不能类型推导出NSArray中存是什么类型的对象,因此多数存在subArray的状况,咱们会选择多层KVC嵌套,或者直接使用for循环来为该对象赋值。
六、KVC在Swift中的差别
在Swift中,KVC的用法又会有所不一样
好比说
var students:[Student]
Swift的array对象再也不拥有KVC的方法
因此咱们不能经过
var studentsName:[String] = students.valueForKeyPath("studentName");
来取出一个集合的纵向数据
固然也并非没有解决方案,咱们能够经过
var studentsName:[String] = self.valueForKeyPath("students.studentName")
这即是Swift 中KVC的一点点小差别
更多内容有待更新(老师忙……)