KVC简称KeyValueCoding,是一个基于NSKeyValueCoding非正式协议的机制,可以允许开发者通过Key名直接访问对象的属性,或者给对象的属性赋值。而不需要调用明确的存取方法。这样就可以在运行时动态访问和修改对象的属性。而不是在编译时确定,这也是iOS开发中的黑魔法之一。很多高级的iOS开发技巧都是基于KVC实现的。
注:NSObject是定义了KVC的,所以继承NSObject的对象都支持KVC,基本上所有的OC对象都支持KVC。
KVC取值
1、 MyObject *obj = [[MyObject alloc] init];
使用属性时@property (nonatomic, strong)NSString *name;
系统会默认生成- (NSString *)name;和- (void)setName:(NSString *)name两个存取方法
则对obj对象的name进行取值,obj.name 执行- (NSString *)name取值方法.
2、在没有主动建立property的情况下,也就是MyObject没有name属性
MyObject *obj = [[MyObject alloc] init];
NSLog(@"%@",[obj valueForKey:@"name”]);
当执行[obj valueForKey:@"name”]时,系统就会根据name来进行一个搜索,那么KVC执行规则是:
搜索
- -(NSString *)getName方法,
- -(NSString*)name方法,
- -(NSString*)isName方法,这三个方法的先后顺序来查找,
如果有,则执行相应的方法,(这是按NSString类型的查找规则)。
如果没有则继续找,因为key:@"name",系统也不知道查找的name是什么类型的,那么系统会按照其他数据类型的方式继续找,如数组NSArray查找方式会找这两个方法 - -(NSUInteger)countOfName
- -(id)objectInNameAtIndex:(NSUInteger)index
如果找到了就执行。依此类推还有其他数据类型的查找方式,不一一例举出来了
按照KVC规则没有查找到相应的方法则会调用valueForUndefinedKey:方法,系统直接抛出异常,程序Crash, 我们可以重写valueForUndefinedKey这个方法,则不会导致系统抛出异常,防止程序奔溃。
因此字典转模型时 字典中key为id时会重命名为uid 处理就在valueForUndefinedKey方法中进行
MyObject.h
#import <Foundation/Foundation.h>
@interface MyObject : NSObject
@end
MyObject.m
@implementation MyObject
- (NSString *)name
{
NSLog(@"%s",__func__);
return @"快乐跑1";
}
- (NSString *)isName
{
NSLog(@"%s",__func__);
return @"快乐跑2";
}
- (NSString *)getName
{
NSLog(@"%s",__func__);
return @"快乐跑3";
}
- (NSInteger)countOfName
{
NSLog(@"%s",__func__);
return 1;
}
- (id)objectInNameAtIndex:(NSUInteger)index
{
NSLog(@"%s",__func__);
return @"快乐跑5";
}
- (id)valueForUndefinedKey:(NSString *)key
{
NSLog(@"%s",__func__);
return @"快乐跑6";
}
@end
KVC存值
MyObject没有定义任何属性
MyObject *obj = [[MyObject alloc] init];
[obj setValue:@"哈哈哈" forKey:@"name"];
调用setValue:forkey:代码时,底层的执行机制:程序会去找
—(void)setName:(NSString *)name属性值方法,如果没有找到- (void)setName:(NSString *)name方法,
KVC机制会检查(BOOL)accessInstanceVariablesDirectly方法有没有返回YES,系统默认是返回YES的,但我们可以重写
如果是返回NO,没找到setName方法,那么系统就会执行setValue:ForUndefineKey:方法,系统抛出异常,程序Crash。
返回YES,继续搜索类里面成员变量,搜索顺序依次是_name、_isName、name、isName,如果找了相应变量,就停止寻找,对该变量进行修改
MyObject.h
#import <Foundation/Foundation.h>
@interface MyObject : NSObject
{
NSString *_name;
NSString *_isName;
NSString *name;
NSString *isName;
}
- (void)printName;
@end
MyObject.m
@implementation MyObject
- (void)printName
{
NSLog(@"_name %@",_name);
NSLog(@"_isName %@",_isName);
NSLog(@"name %@",name);
NSLog(@"isName %@",isName);
}
+ (BOOL)accessInstanceVariablesDirectly
{
return NO;
}
@end
网友评论