美文网首页
KVC 访问对象 / 集合属性

KVC 访问对象 / 集合属性

作者: 哆啦_ | 来源:发表于2018-05-09 20:29 被阅读88次

    一个对象通常在interface声明它的property,这些property属于以下类别之一:

    • Attributes. 比如基本数据类型,字符串,或者布尔值。值类型比如NSNumber和其他不可变类型(如NSColor)也被视为属性

    • To-one 关系. 这些是具有自己属性的可变对象。一个对象的属性可以在对象本身不变的情况下改变。比如,一个bankAccount可能拥有一个owner属性,该属性是一个Person对象的实例,owner有一个address属性,这个owneraddress可能改变,而不会更改bankAccountowner的资料。

    • To-many 关系.这些是集合对象,一般是NSArray或者NSSet的实例对象,当然也可以自定义集合类型。

    比如list 2-1描述
    list 2-1

    @interface BankAccount : NSObject
    @property (nonatomic) NSNumber* currentBalance;              // An attribute
    @property (nonatomic) Person* owner;                         // A to-one relation
    @property (nonatomic) NSArray< Transaction* >* transactions; // A to-many relation
    @end
    

    我们通常会为interface的属性提供一些访问方法。或明确地写出这些方法,或者依赖编译器自动生成这些方法。无论哪种方式,使用这些方法的时候必须在编译之前声明这些属性。这些方法的名称会成为代码的静态部分。比如,在表2-1中,声明了一个BankAccount对象,编译器生成了一个setter方法,可以被myAccount实例调用

    [myAccount setCurrentBalance:@(100.0)];
    

    这是一种很直接的方法,但缺少一些灵活性。KVC提供了一种更加通用的机制(使用字符串标识符)来访问对象的属性。

    通过Key和Key Path来标识对象的属性

    key是标识特定属性的字符串。通常,根据约定,标识属性的key是属性自身的名字。 key必须是使用ASCII编码,不能含有空格,并且通常使用小写字母开头(也存在例外,比如在许多类中的URL属性.

    由于表2-1中的BankAccount类是支持KVC的,因此它可以识别这些key:owner,currentBalance, 和 transactions,它们都是属性的名称。可以不使用setCurrentBalance:方法,而是通过key来设置value

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

    事实上,我们可以通过相同的方法传递不同的参数key来设置myAccount对象的所有属性。因为参数是个字符串,所以可以作为变量在运行时进行操作或者修改。

    key path是一个以圆点隔开的字符串,用来指定要遍历的对象属性。在序列中的第一个key的属性是相对于receiver的,后续的key都相对于前一个属性的值进行评估。key path对于用单个方法深入到对象的层次结构非常有用。

    比如,owner.address.street路径指就是存储在银行账号的所有者地址中的street字符串的值,假设PersonAddress类也是支持KVC的.

    使用key获取属性值

    当对象采用了NSKeyValueCoding协议时就会支持KVC。NSObject提供了该协议的必要方法的默认实现,所以当一个继承自NSObject的对象,会自动遵守这个协议。并且至少实现了下面的基于key的getter方法

    • valueForKey: 返回名字为参数key的属性的值。如果根据访问查询规则没有找到key名称的属性,会向自身发送一个valueForUndefinedKey:消息。valueForUndefinedKey:默认会抛出NSUndefinedKeyException异常,但子类可以实现该方法做一些更合适的操作.

    • valueForKeyPath: 返回receiver的指定路径的值。在key path序列中任何不支持kvc的对象(即valueForKey:的默认实现不能找到访问方法)都会收到valueForUndefinedKey:消息。

      [object valueForKeyPath:@"a.b.c"]
      等效于 [[[object valueForKey:@"a"] valueForKey:@"b"] valueForKey:@"c"]

    • dictionaryWithValuesForKeys: 通过数组keys(存放的都是key),为receiver返回一个字典。这个方法为数组keys中每个key调用valueForKey:方法,然后返回一个字典,字典中包含了数组中所有key对应的value。

    需要注意的是,集合对象,比如NSArray, NSSet, NSDictionary,不能含有nil。可以使用NSNull对象来表示nil.dictionaryWithValuesForKeys:以及与其相关的setValuesForKeysWithDictionary:方法的默认实现是:自动在NSNull(在字典的参数中)和nil(在存储的属性中)之间进行转换

    使用key设置属性值

    与getter一样,支持KVC的对象同样提供了一组基于NSObjectNSKeyValueCoding协议实现的默认行为的通用setter。

    • setValue:forKey:receiverkey属性的值设置为给定的value.setValue:forKey:方法的默认实现会自动将表示基本数据变量和结构体的NSNumberNSValue对象解包(解包为基本数据类型或者结构体),并将它们赋值给属性。

      如果收到setter调用的对象的属性没有指定的key,对象会给自己发送一个setValue:forUndefinedKey:消息,setValue:forUndefinedKey:默认会抛出NSUndefinedKeyException异常。

    • setValue:forKeyPath: 将给定的值设置给reciver的指定路径。在key path序列中有key不支持kvc的话会收到setValue:forUndefinedKey:消息。

    • setValuesForKeysWithDictionary: 使用字典中的key来标识属性,将receiver的属性设置为字典中的value.该方法的默认实现是为每个键值对调用setValue:forKey:(根据需要将nil替代为NSNull

        Person *per = [[Person alloc] init];
        per.age = 18;
        
        BankAccount *account = [[BankAccount alloc] init];
        
        NSDictionary *dict = @{@"currentBalance":@(20),
                               @"owner":per,
                               };
        [account setValuesForKeysWithDictionary:dict];
        
        NSLog(@"account: %@", account);
      

    当想要给一个非对象属性设置一个nil值时,kvc对象会给自己发送一个setNilValueForKey:消息,setNilValueForKey:默认会抛出NSInvalidArgumentException异常,但是对象可以覆盖该行为,以替换默认值或标记值。

    访问集合属性

    KVC对象以与公开它的其他属性同样的方式公开它的to-many属性。可以使用valueForKey:setValue:forKey:(或者其他等同于keypath的路径)get或set一个集合属性,但是,当想要操作集合里的内容时,使用协议定义的可变代理方法通常是最有效率的。

    协议为集合对象的访问定义了三种不同的代理方法,每一种方法都有一个keykeyPath.

    • mutableArrayValueForKey:mutableArrayValueForKeyPath: 这些方法返回一个类似于NSMutableArray的代理对象。

    • mutableSetValueForKey:mutableSetValueForKeyPath:这些方法返回一个类似于NSMutableSet的代理对象。

    • mutableOrderedSetValueForKey:mutableOrderedSetValueForKeyPath: 返回一个类似于NSMutableOrderedSet的对象。

    当你对该代理对象进行添加对象、 删除对象、 或者插入对象操作时,协议的默认实现会修改相应的底层属性。这比通过valueForKey:方法获取一个不可变的集合属性更加有效率,通过修改过的内容创建一个修改的对象,然后通过setValue:forKey:将其存储回对象。许多情况下,它比直接使用可变属性更加有效。这些方法更有利于集合中对象的KVO。

    相关文章

      网友评论

          本文标题:KVC 访问对象 / 集合属性

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