KVC与Json Model

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的地方有:

  1. 访问成员变量。
  2. xib。控件的所有属性不可能都显示在面板里,User Define Runtime Attributes就是通过KVC来设置
  3. 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

  • http://www.jianshu.com/p/cb3d8b696c00
  • http://blog.ibireme.com/2015/10/23/ios_model_framework_benchmark/
  • https://github.com/gongjiehong/JsonModel-Use-KVC/blob/master/CreatClassFromJson/JsonBaseModel.m

你可能感兴趣的:(KVC与Json Model)