刨根問底KVC
KVC 全稱 key valued coding 鍵值編碼html
反射機制是在運行狀態中,對於任意一個類,都可以知道這個類的全部屬性和方法;對於任意一個對象,都可以調用它的任意一個方法和屬性.JAVA,C#都有這個機制。ObjC也有,因此你根部沒必要進行任何操做就能夠進行屬性的動態讀寫,就是KVC。ios
KVC的操做方法由NSKeyValueCoding提供,而他是NSObject的類別,也就是說ObjC中幾乎全部的對象都支持KVC操做。服務器
Person.happ
1 2 3 4 5 6 7 8 9 10 11 12
|
@interface Person : NSObject { int weight; } @property(nonatomic,readonly,copy) NSString *name; @property(nonatomic,readonly, assign) int age; @property(nonatomic,strong) Dog * dog; @property(nonatomic,assign) id ID;
-(instancetype)initWithDict:(NSDictionary *)dict;
@end
|
Person.mui
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
|
@implementation Person { int _height; }
-(instancetype)initWithDict:(NSDictionary *)dict { if (self=[super init]) { |
main.m編碼
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
|
Person * p1 = [[Person alloc]init]; Dog * d1 = [[Dog alloc] init]; p1.dog = d1;
|
KVC查找屬性的順序
- 用@property定義的屬性的key值
- setter方法的key值
- 直接訪問成員變量,先找key,若是找不到,再找_key
- 以上三種都未找到就會調用- (void)setValue:(id)value forUndefinedKey:(NSString *)key 方法。
- 若是沒有重寫setValue:forUndefinedKey程序會立刻崩潰。
注意:KVC能夠訪問成員變量,不管是否提供getter/setter方法,不管可見性是怎樣,是否有readonly修飾。atom
setValue:forUndefinedKey與valueForUndefinedKey的應用
KVC的主要用途無非是ORM映射,就是將dictionary轉換成model,但有些服務器返回的字段有多是oc的關鍵字好比‘id’,’description’等。如上代碼舉得id的例子,咱們沒法讓@property後面key值爲id,因而使用大寫的ID代替,KVC是區分大小寫的咱們不用擔憂。這時咱們只需在setValue:forUndefinedKey把id的key值賦值給ID的key值,就能夠避免關鍵字的尷尬。spa
KVC的逆向使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
|
Person * p1 = [[Person alloc]init]; [p1 setValue:@"170" forKey:@"height"]; [p1 setValue:@"70" forKey:@"weight"]; [p1 setValue:@"11111" forKey:@"id"];
NSArray * arr = @[@"height",@"weight",@"id"]; NSDictionary * dict = [p1 dictionaryWithValuesForKeys:arr]; NSLog(@"%@",dict);
log日誌: { height = 170; id = 11111; weight = 70; }
|
NSArray/NSSet等都支持KVC
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
|
Person * p1 = [[Person alloc]init]; Dog * d1 = [[Dog alloc] init]; d1.name = @"iPhone"; p1.dog = d1; Person * p2 = [[Person alloc]init]; Dog * d2 = [[Dog alloc] init]; d2.name = @"ios"; p2.dog = d2;
NSArray *persons=@[p1,p2]; NSArray *arrayM=[persons valueForKeyPath:@"dog.name"]; NSLog(@"%@",arrayM);
log日誌: ( iPhone, ios )
|
KVC計算
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
|
Person * person = [[Person alloc] init];
NSMutableArray * books = [NSMutableArray array]; for (int i = 0; i < 10; i++) { Book * book = [[Book alloc] init]; book.price = i; [books addObject:book]; }
person.books = books;
NSNumber *bookCount = [person valueForKeyPath:@"books.@count"]; NSLog(@"book count :%@", bookCount);
NSNumber *sum = [person valueForKeyPath:@"books.@sum.price"]; NSLog(@"sum :%@", sum);
NSNumber *avg = [person valueForKeyPath:@"books.@avg.price"]; NSLog(@"vag :%@", avg);
NSNumber *min = [person valueForKeyPath:@"books.@min.price"]; NSLog(@"min :%@", min);
NSNumber *max = [person valueForKeyPath:@"books.@max.price"]; NSLog(@"max :%@", max);
|
KVC底層實現
1 2 3 4 5 6 7 8 9
|
好比說以下的一行KVC的代碼: [person setValue:@"dahuan" forKey:@"name"]; 就會被編譯器處理成: SEL sel = sel_get_uid ("setValue:forKey:"); IMP method = objc_msg_lookup (person->isa,sel); method(person, sel, @"dahuan", @"name");
|
KVC與runtime應用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
|
#import "MyModel.h" #import <objc/runtime.h> @implementation MyModel
|
最後附蘋果KVC官方文檔:日誌
https://developer.apple.com/library/mac/documentation/General/Conceptual/DevPedia-CocoaCore/KeyValueCoding.htmlcode
另外.....
個人願望是.......
世界和平.........