刨根问底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
另外.....
个人愿望是.......
世界和平.........