KVC是动态获取或设置对象属性/成员变量的方法。就是我们常见的valueForKey:
和setValue:forKey:
。
KVC还支持集合操作和key path,个人认为这有点炫技成分。
官方文档:https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/KeyValueCoding/index.html#//apple_ref/doc/uid/10000107-SW1
经常用到KVC的地方有:
- 访问成员变量。
- xib。控件的所有属性不可能都显示在面板里,User Define Runtime Attributes就是通过KVC来设置
- Dictionary <-> Object。
Dictionary <-> Object
KVC在这个场景特别流行,setValuesForKeysWithDictionary:
功不可没。
- (id)initWithDictionary:(NSDictionary *)jsonDic
{
self = [super init];
if (self != nil)
{
[self setValuesForKeysWithDictionary:jsonDic];
int i;
unsigned int propertyCount = 0;
objc_property_t *propertyList = class_copyPropertyList([self class], &propertyCount);
for ( i=0; i < propertyCount; i++ )
{
objc_property_t *thisProperty = propertyList + i;
const char* propertyName = property_getName(*thisProperty);
NSString *propertyKeyName = [NSString stringWithUTF8String:propertyName];
if ([[jsonDic valueForKey:propertyKeyName] isKindOfClass:[NSDictionary class]])
{
id object = [[[self getItemClassWithPropretyName:propertyKeyName] alloc] initWithDictionary:[jsonDic valueForKey:propertyKeyName]];
[self setValue:object forKey:propertyKeyName];
}
else if ([[jsonDic valueForKey:propertyKeyName] isKindOfClass:[NSArray class]])
{
NSMutableArray *arr = [NSMutableArray array];
for (id object in [jsonDic valueForKey:propertyKeyName])
{
if ([object isKindOfClass:[NSDictionary class]])
{
[arr addObject:[[[self getItemClassWithPropretyName:propertyKeyName] alloc] initWithDictionary:object]];
}
else
{
[arr addObject:object];
}
}
[self setValue:arr forKey:propertyKeyName];
}
}
}
return self;
}
-(Class)getItemClassWithPropretyName:(NSString *)name
{
// 检查 Class 是否实现了 initWithDictionary:
}
setValuesForKeysWithDictionary:
处理不了集合类型,所有以得单独处理。
性能
KVC的搜索还挺复杂的
对于setValue:属性值 forKey:@"name";代码,底层的执行机制如下:
(1).程序优先调用“setName:属性值;”代码通过setter方法完成设置。
(2).如果该类没有setName:方法,KVC机制会搜索该类名为_name的成员变量,找到后对_name成员变量赋值。
(3).如果该类既没有setName:方法,也没有定义_name成员变量,KVC机制会搜索该类名为name的成员变量,找到后对name成员变量赋值。
(4).如果上面3条都没有找到,系统将会执行该对象的setValue: forUndefinedKey:方法。默认setValue: forUndefinedKey:方法会引发一个异常,将会导致程序崩溃。
对于“valueForKey:@"name";”代码,底层执行机制如下:
(1).程序优先调用"name;"代码来获取该getter方法的返回值。
(2).如果该类没有name方法,KVC机制会搜索该类名为_name的成员变量,找到后返回_name成员变量的值。
(3).如果该类既没有name方法,也没有定义_name成员变量,KVC机制会搜索该类名为name的成员变量,找到后返回name成员变量的值。
(4).如果上面3条都没有找到,系统将会执行该对象的valueForUndefinedKey:方法。默认valueForUndefinedKey:方法会引发一个异常,将会导致程序崩溃。
性能差于直接调用 Getter/Setter,如果能直接访问 ivar效率更高。
Refrence