Objective,object
KVC的使用
1、KVC 全稱 key valued coding 索引值編碼
反射機制是在運行狀態中,對於任意一個類,都能夠知道這個類的所有屬性和方法;對於任意一個對象,都能夠調用它的任意一個方法和屬性.JAVA,C#都有這個機制。ObjC也有,所以你根部不必進行任何操作就可以進行屬性的動態讀寫,就是KVC。
KVC的操作方法由NSKeyValueCoding提供,而他是NSObject的類別,也就是說ObjC中幾乎所有的對象都支援KVC操作。
2、常用方法
擷取值的方法
valueForKey:,傳入NSString屬性的名字。
valueForKeyPath:,傳入NSString屬性的路徑,xx.xx形式。
valueForUndefinedKey它的預設實現是拋出異常,可以重寫這個函數做錯誤處理。
那麼問題來了 現在有連個類,Book類(對應屬性:name,prices)和Person類(對應屬性:name,height,Book *book),person有一本名字叫做《太陽的後裔》,那麼現在想通過KVC給這本書賦值,應該如何操作?
個人總結答案:因為現在想修改的不是對應類也就是Person類的屬性,是要修改Book的屬性(person.book),所以需要通過valueForKeyPath來進行修改^_^
修改值的方法
setValue:forKey:
setValue:forKeyPath:
setValue:forUndefinedKey:
setValue:forKey的搜尋過程:
注意:
1、使用KVC間接修改對象屬性時,系統會自動判斷對象屬性的類型,並完成轉換。
2、KVC可以訪問成員變數,無論是否提供getter/setter方法,無論可見度是怎樣,是否有readonly修飾。
setValue:forUndefinedKey與valueForUndefinedKey的應用
KVC的主要用途無非是ORM映射,就是將dictionary轉換成model,但有些伺服器返回的欄位有可能是oc的關鍵字比如‘id’,’description’等。如上代碼舉得id的例子,我們無法讓@property後面key值為id,於是使用大寫的ID代替,KVC是區分大小寫我們不用擔心。這時我們只需在setValue:forUndefinedKey把id的key值賦值給ID的key值,就可以避免關鍵字的尷尬。
3、dict <->model 互轉
字典轉模型
[self setValuesForKeysWithDictionary:dict];
模型轉字典
[p dictionaryWithValuesForKeys:array];
4、KVC集合
NSArray/NSSet等都支援KVC
[array valueForKeyPath:@"dog.name"];
5、使用KVC計算屬性
格式為:[p valueForKeyPath:@"Left keypath部分.@Collectionoperator部分.Right keypath部分”];
Left keypath部分:需要操作物件路徑。
Collectionoperator部分:通過@符號確定使用的集合操作。
Right keypath部分:需要進行集合操作的屬性。
舉例:[p valueForKeyPath:@"books.@sum.price"];
@avg:平均值
@count:總數
@max:最大
@min:最小
@sum:總數
6、具體代碼與實際編輯
1)當使用KVC給對象的屬性賦值時,當根據輸入的Key值沒有找到對應的Value時調用
1 - (void)setValue:(id)value forUndefinedKey:(NSString *)key {2 3 NSLog(@"key = %@沒有找到",key);4 5 }
2)當找到了對應的key值,代碼為
1 // 2 // main.m 3 // KVC熟悉與加強 4 // 5 // Created by ma c on 16/5/16. 6 // Copyright © 2016年 彭盛凇. All rights reserved. 7 // 8 9 #import <Foundation/Foundation.h>10 11 #import "Model.h"12 13 int main(int argc, const char * argv[]) {14 @autoreleasepool {15 16 Model *model = [[Model alloc] init];17 18 [model setValue:@"Coder丶PSS" forKey:@"name"];19 [model setValue:@"178" forKeyPath:@"height"];20 21 // NSLog(@"%@",model);22 23 NSLog(@"名字叫%@,身高為%@",[model valueForKey:@"name"],[model valueForKey:@"height"]);24 25 26 27 }28 return 0;29 }
結果為:
3)使用原生方法解析資料
因為本人沒有伺服器,寫了個假資料(plist),進行解析,效果是一樣的
(1)plist:
(2)解析資料代碼
model.m
1 // 2 // Model.h 3 // KVC熟悉與加強 4 // 5 // Created by ma c on 16/5/16. 6 // Copyright © 2016年 彭盛凇. All rights reserved. 7 // 8 9 #import <Foundation/Foundation.h>10 11 @interface Model : NSObject12 13 @property (nonatomic, copy, readonly) NSString *name;14 15 @property (nonatomic, assign, readonly) NSInteger height;16 17 + (NSArray *)loadData;18 19 @end
model.h
1 // 2 // Model.m 3 // KVC熟悉與加強 4 // 5 // Created by ma c on 16/5/16. 6 // Copyright © 2016年 彭盛凇. All rights reserved. 7 // 8 9 #import "Model.h"10 11 @implementation Model12 13 - (NSString *)description14 {15 return [NSString stringWithFormat:@"model.name = %@, mdoel.height = %@", _name, @(_height)];16 }17 18 - (void)setValue:(id)value forUndefinedKey:(NSString *)key {19 20 NSLog(@"key = %@沒有找到",key);21 22 }23 24 + (NSArray *)loadData {25 26 //擷取plist檔案路徑27 NSString *path = @"/Users/mac/Desktop/KVC熟悉與加強/KVC熟悉與加強/CoderPSS.plist";28 29 //擷取plist檔案中的數組30 NSArray *array = [NSArray arrayWithContentsOfFile:path];31 32 //初始化可變數組33 NSMutableArray *dataList = [NSMutableArray array];34 35 //使用字典遍曆plist中的數組36 for (NSDictionary *dict in array) {37 38 //初始化model類39 Model *model = [[Model alloc] init];40 41 //使用KVC(setValuesForKeysWithDictionary)方法解析資料42 [model setValuesForKeysWithDictionary:dict];43 44 //將model類加到可變數組45 [dataList addObject:model];46 }47 48 //返回可變數組49 return dataList;50 }51 52 @end
運行結果