除了: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的一點點小差別
更多內容有待更新(老師忙……)