美文网首页
iOS_KVC_分析

iOS_KVC_分析

作者: 自律_自强_通达 | 来源:发表于2018-08-31 11:50 被阅读0次

    本文主要转载,原文链接 http://www.cocoachina.com/ios/20180305/22441.html
    也参考了其他资料

    一、概念定义

    KVC(Key-value Coding/键值编码) :是一个非正式协议,提供了可以通过字符串间接访问类属性、方法或成员变量的一种机制。而不是通过setter 和getter 方法。(SomeBody say,KVO就是基于KVC实现的关键技术之一)

    二、基础操作

    KVC主要对三种类型进行操作,基础数据类型及常量对象类型集合类型

    @interface BankAccount : NSObject
    @property (nonatomic, strong) NSNumber *currentBalance;
    @property (nonatomic, strong) Person *owner;
    @property (nonatomic, strong) NSArray<transaction *> *transactions;
    @end</transaction *>
    

    在使用KVC时,直接将属性名当做key,并设置value,即可对属性进行赋值。

    [myAccount setValue:@(100.0) forKey:@"currentBalance"];
    

    三、keyPath

    除了对当前对象“属性”进行赋值外,还可以对更“深层”的对象进行赋值。例如:对当前对象的address属性的 street 属性进行赋值。KVC进行多级访问时,可直接利用点语法调用即可。

    [myAccount setValue:@"回龙观东大街" forKey:"adress.street"];
    

    通过keyPath对数组进行取值的时候,并且数组的对象类型都相同,可以通过valueForKeyPath:方法指定取出数组中所有对象的某个字段。例如下面这个例子:通过valueForKeyPath:方法获取数组中所有对象的name属性值,返回放入一个数组中。

    NSArray *namesArr = [array valueForKeyPath:@"name"];
    

    四、多值操作

    需要注意的是,下面两个例子虽然看到了dictionary字样,但这些并不是字典的方法。

    KVC强大的地方还有,可以根据一组key获取一组 value,并以字典的形式返回,获取到字典后,就可以通过key 获取value值了。

    - (NSDictionary<nsstring *, id> *)dictionaryWithValuesForKeys:(NSArray<nsstring *> *)keys;</nsstring *></nsstring *, id>
    

    同样也可以批量赋值。在对象调用setValuesForKeysWithDictionary:方法的时候,可以传入包含key、value的字典,KVC就可以讲所有的数据按照属性名按照字典的key进行匹配,并将value赋值给对象的相应

    - (void)setValuesForKeysWithDictionary:(NSDictionary<nsstring *, id> *)keyedValues;</nsstring *, id>
    

    五、实用技巧

    在开发中,最常遇到的就是将字典转模型。如果在自定义的init 方法中逐个赋值,这样每次数据发生改变的时候,还需要修改赋值语句。然而,通过KVC为我们提供的赋值API,可以对数据进行批量赋值。假设,有一下json数据,并定义User类,在外界通过setValuesForKeysWithDictionary:方法对User进行赋值。

    JSON数据:
    {
        "username": "lxz",
        "age": 25,
        "id": 100
    }
     
    @interface User : NSObject
    @property (nonatomic, copy) NSString *name;
    @property (nonatomic, assign) NSInteger age;
    @property (nonatomic, assign) NSInteger userId;
    @end
     
    @implementation User
    - (void)setValue:(id)value forUndefinedKey:(NSString *)key {
        if ([key isEqualToString:@"id"]) {
            self.userId = [value integerValue];
        }
    }
    @end
    

    赋值时会遇到一些问题,例如服务器会返回一个id字段,但是对于客户端来说id是系统保留字段,可以重写setValue:forUndefinedKey:方法并在内部处理id参数的赋值。

    转换时需要服务器数据和类定义匹配,字段数量和字段名都应该匹配。如果User比服务器数据多,则服务器没传的字段为空。如果服务端传递的数据User中没有定义,则会导致崩溃。

    在KVC进行属性赋值时,内部会对基础数据类型做处理,不需要手动做NSNumber的转换。需要注意的是,NSArray和NSDictionary等集合对象,value都不能是nil,否则会导致Crash。

    六、异常信息

    当通过KVC给某个非对象的属性赋值为nil时,此时KVC会调用属性所属对象的setNilValueForKey:方法,并抛出NSInvalidArgumentException的异常,并使应用程序Crash。

    我们可以通过重写下面方法,在发生这种异常时进行处理。例如给name赋值为nil的时候,就可以重写setNilValueForKey:方法并表示name是空的。

    - (void)setNilValueForKey:(NSString *)key {
        if ([key isEqualToString:@"name"]) {
            [self setValue:@"" forKey:@”age”];
        } else {
            [super setNilValueForKey:key];
        }
    }
    

    集合属性操作

    根据KVO的实现原理,是在运行时生成新的子类并重写其setter方法,在其内容发生改变时发送消息。但这只是对属性直接进行赋值会触发,如果属性是容器对象,对容器对象进行add或remove操作,则不会调用KVO的方法。可以通过KVC对应的API来配合使用,使容器对象内部发生改变时也能触发KVO。

    在进行容器对象操作时,先调用下面方法通过key或者keyPath获取集合对象,然后再对容器对象进行add或remove等操作时,就会触发KVO的消息通知了。

    (未完待续:KVC实现原理)

    相关文章

      网友评论

          本文标题:iOS_KVC_分析

          本文链接:https://www.haomeiwen.com/subject/qzdswftx.html