16

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

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

而不是写

[myObject setBar:foo];

甚至

myObject.bar = foo;

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

4

3 回答 3

24

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

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

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

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

另一个直到运行时才知道要访问哪个属性的例子是 Core Animation (鲜为人知)能够为CALayer子类的自定义属性设置动画。假设您创建了一个CALayer名为的子类PolygonLayer,并具有一个名为 的属性sidessides您可以使用标准为属性设置动画CABasicAnimation

CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"sides"];
animation.fromValue = @3;
animation.toValue = @9;
animation.autoreverses = YES;
animation.duration = 1;
[myPolygonLayer addAnimation:animation forKey:@"sides"];

sidesPresto,Core Animation 将为您的图层属性设置动画,从 3 到 9 并返回。sides然而,Core Animation 的源代码对您的属性一无所知。(查看这个问题了解更多详情。)

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

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

但在这种情况下,KVC 具有使其更简单的功能。如果您使用 KVC 访问数组的属性,KVC 实际上会为您访问数组中每个元素的该属性:

NSArray *firstNames = [people valueForKey:@"firstName"];

即使我们在编译时知道属性,我们也可能使用 KVC 的另一个示例是,当属性未静态声明为类的一部分时。例如,每个 NSManagedObject(Core Data 的一部分)根据该实例NSManagedObject所代表的任何实体动态地赋予自己属性。您可以使用 KVC 访问这些属性,尽管通常我们更喜欢将它们声明NSManagedObjectNSManagedObject.

于 2012-11-14T19:58:12.040 回答
0

如果您使用 Key Value Observers 来检测对象上的值变化,KVC 会很有用。如果您想使用 KVO,并且@properties您必须将每个 mutator 方法包​​装为:

[self willChangeValueForKey:@"bar"];
bar = foo;
[self didChangeValueForKey:@"bar"];
于 2012-11-14T19:55:44.923 回答
0

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

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

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

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

[object setValue:[NSDate date] forKey:[NSString stringWithFormat:@"%@%@", arrayString, @"LastModified"];
于 2012-11-14T20:06:46.077 回答