键值编码有什么意义?

时间:2012-11-14 19:40:52

标签: objective-c

自Objective-C 2.0以来,我们已经拥有@properties和自动生成的访问器方法。那么今天,键值编码有什么意义呢?在什么情况下最好写

[myObject setValue:foo forKey:@"bar"];

而不是写

[myObject setBar:foo];

甚至

myObject.bar = foo;

我一直看到使用KVC的文章和文档,但总是以一种似乎只是简单地使用属性的方式会更好。那我为什么要用KVC呢?感谢您的任何见解。

3 个答案:

答案 0 :(得分:20)

用文字[myObject setValue:foo forKey:@"bar"]手写出@"bar"几乎不可取。当我们在运行时不知道要访问哪个属性时,我们通常使用KVC来访问属性。

一个例子是xib中的插座。当您将文本字段的委托出口连接到xib中的文件所有者时,xib将连接记录为具有三个字段的对象:

  • 对文本字段(具有插座的对象)的引用
  • 对文件所有者占位符(连接目标)的引用
  • 插座名称为@"delegate"

在运行时,xib加载程序(UIKit框架的一部分)反序列化文本字段。然后它反序列化连接对象并使用它来建立您在xib中连接的连接。 xib加载器必须设置文本字段的属性(delegate属性),但在编译应用程序和UIKit框架很久之后,它在运行时加载xib之前不知道哪个属性。

另一个不知道在运行时访问哪个属性的例子是Core Animation为CALayer子类的自定义属性设置动画的(鲜为人知的)能力。假设您创建一个名为CALayer的{​​{1}}子类,其属性名为PolygonLayer。您可以使用标准sides

sides属性设置动画
CABasicAnimation

Presto,Core Animation会将图层的CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"sides"]; animation.fromValue = @3; animation.toValue = @9; animation.autoreverses = YES; animation.duration = 1; [myPolygonLayer addAnimation:animation forKey:@"sides"]; 属性设置为3到9并返回。然而,Core Animation的源代码对sides属性一无所知。 (查看this question了解更多详情。)

我们有时会使用KVC,即使我们在编译时知道属性。一个例子是我们想利用KVC为我们做的额外工作。例如,如果您有sidesNSArray个对象,并且想要获得每个人的名字数组,那么您可以这样写:

Person

但是,这是KVC具有使其更简单的功能的情况。如果使用KVC访问数组的属性,KVC将实际访问数组中每个元素的属性:

NSMutableArray *firstNames = [NSMutableArray array];
for (Person *person in people) {
    [firstNames addObject:person.firstName];
}

我们可能使用KVC的另一个例子,即使我们在编译时知道属性,也就是当属性没有被静态声明为类的一部分时。例如,每个NSManagedObject(Core Data的一部分)根据NSArray *firstNames = [people valueForKey:@"firstName"]; 实例所代表的任何实体动态地为其自身提供属性。您可以使用KVC访问这些属性,但通常我们更喜欢declare them in a subclass of NSManagedObject or in a category of NSManagedObject

答案 1 :(得分:0)

如果使用键值观察器检测对象的值更改,则KVC非常有用。如果你想使用KVO和@properties,你必须用每个mutator方法包装:

[self willChangeValueForKey:@"bar"];
bar = foo;
[self didChangeValueForKey:@"bar"];

答案 2 :(得分:0)

有时候你不知道在运行时要设置/获取什么属性 在这种情况下,您可以通过将属性键路径构造为字符串来使用KVC。

例如,我有一个具有多个NSArray属性的对象,我想保留它们被更新的最后一个NSDate。

假设我有一个名为: comments 的数组属性和一个名为的数组属性

我定义了一个属性:commentsLastModified和likesLastModified。 当一个数组更新(我有属性名称为字符串),我使用:

[object setValue:[NSDate date] forKey:[NSString stringWithFormat:@"%@%@", arrayString, @"LastModified"];