Key-Value Coding

本文详细介绍了Key-Value Coding(KVC),一种通过字符串间接访问对象属性的技术,广泛应用于Key-Value Observing、Core Data等场景。KVC提供了便捷的方式来访问和设置属性,包括属性的获取、设置、键值验证以及对集合操作的支持。文章还讨论了KVC的实现细节,如访问器方法、集合操作符和对标量、结构体的支持。
摘要由CSDN通过智能技术生成

介绍

Key-Value Coding简称KVC,中文名为键值编码。它是一种利用字符串间接访问对象属性的方法。而这个字符串便就是键。访问器,即setter和getter,也是一种间接访问对象属性的方法,只不过在有些场合更加适合使用KVC。虽然KVC在业务逻辑中很少会使用,但在Key-Value Observing,Core Data, Cocoa bindings, scripatability这些模式或者高级特性的基础,因此KVC很重要。

在如下场合,利用KVC明显比利用访问器来得方便。假设一个要从model层获取所有联系人显示到NSTableView上(Cocoa里的列表)。最普通的方式如下:

- (id)tableView:(NSTableView *)tableview
      objectValueForTableColumn:(id)column row:(NSInteger)row {

    Person *person = [contact objectAtIndex:row];
    if ([[column identifier] isEqualToString:@"name"]) {
        return [person name];
    }
    if ([[column identifier] isEqualToString:@"age"]) {
        return [person age];
    }
    if ([[column identifier] isEqualToString:@"favoriteColor"]) {
        return [person favoriteColor];
    }
    // And so on.
}

仔细想想,如果一个person的属性很多,那么代码会变得十分庞大,并且很难维护,如果利用KVC则会简洁得多

- (id)tableView:(NSTableView *)tableview
      objectValueForTableColumn:(id)column row:(NSInteger)row {

    Person *person = [contact objectAtIndex:row];
    return [person valueForKey:[column identifier]];
}

PS: 这里不理解KVC没关系,可以看完后面的实现,再来体会这里。

相关术语

在介绍如何实现KVC之前,先介绍几个接下来要使用的术语:

  • attribute. 它是一个简单属性,不存在一对一关系,一对多关系,只是描述某个事物的一个方面,不和其他对象产生任何联系。例如:标量,字符串,布尔值,NSNumber以及其他不可变的对象如NSColor等。
  • to-one relationship. 它反映的一对一关系属性,与之对应的对象和它独立变化。例如:UIView的superView就是一个to-one relationship属性。
  • to-many relationship. 它反映的是一对多属性关系,通常用集合来表示这样的关系。例如:NSArray, NSSet等。当然也可以利用后面介绍的方法,来自定义KVC的访问方式,在宏观上反映出一对多属性关系。
  • key. key就是一个唯一标识对象属性的字符串。通常就是属性名,如person的name属性,则key=”name”。当然可以自定义,它与具体KVC的访问方法的实现或者实例变量有关,后面会介绍。
  • key path. key path是利用“.”分割的一串字符串,用来标识一系列对象属性的层层穿越。例如一个国家有好多城市,一个城市有很多街道,则如果我拥有国家这个对象country,要访问到这个国家的中的某条街道,则key path=”country.city.street”

具体实现

获取attribute简单属性的方法

[object valueForKey: @"keywords"];

object: 拥有属性的对象。
keywords: 唯一标识属性的字符串key。

举例,例如要访问一个人person的名字name属性.

[person valueForKey: @"name"];

当然除了这样,还需要通过指定对应的访问器,来将key和属性产生关系。

-(void)setName: (NSString *)name
{
    self.name = name;
}

-(NSString *)name
{
    return self.name;
}

看起来和setter,getter几乎是一模一样的,没错,就是一模一样。KVC的访问器,和关联属性的key有关。其内容在后面一节介绍。这里你仅需知道,它不是一般意义上的setter,getter访问器。

如果没有指定KVC访问器,那么接收对象会给自己发一个valueForUndefinedKey:消息。而这个消息在NSKeyValueCoding中定义,其默认实现是抛出一个NSUndefinedKeyException异常。你可以通过重写这个方法,来达到自定义需求。

相类似的,利用key path实现:

[object valueForKeyPath: @"parentKey.subKey"];

object: 拥有属性的对象。
parentKey.subKey: 唯一标识属性路径的字符串key path。

举个例子,访问一个国家的某个城市的,某个街道

[country valueForKeyPath: @"city.street"];

在key path的每个子路径都需要实现与之对应的KVC访问器,如果其中任何一个没有与之对应的访问器,则出出发valueForUndefinedKey:消息。

PS: 如果country的城市属性是一个集合citys,而每个城市又有街道的集合streets,则通过”citys.streets”这个key path会返回这个国家中所有城市的所有街道。

当然如果你想在一个语句中获取多个属性值,则利用dictionaryWithValuesForKeys:方法会返回一个NSDictionary,里面包含属性的key和对应属性的值。

PS: 在集合对象中,NSArray, NSSet, NSDictionary不能包含nil来表示空值,因为nil表示集合结束。如果要表示空值,请用NSNull,NSNull是一个单例类。[NS

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值