自Objective-C 2.0以来,我们已经拥有@properties
和自动生成的访问器方法。那么今天,键值编码有什么意义呢?在什么情况下最好写
[myObject setValue:foo forKey:@"bar"];
而不是写
[myObject setBar:foo];
甚至
myObject.bar = foo;
我一直看到使用KVC的文章和文档,但总是以一种似乎只是简单地使用属性的方式会更好。那我为什么要用KVC呢?感谢您的任何见解。
答案 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为我们做的额外工作。例如,如果您有sides
个NSArray
个对象,并且想要获得每个人的名字数组,那么您可以这样写:
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"];