16

我试图更好地理解 Cocoa 的键值编码 (KVC) 机制。我已经阅读了 Apple 的Key-Value Programming Guide,但对于某些 KVC 方法如何搜索键仍然有些困惑。特别是mutableArrayValueForKey:

下面我将解释我如何理解valueForKey:KVC “getter”的工作原理。然后我会回答关于 mutableArrayValueForKey 的问题。


有七种不同的“getter”KVC 方法:

- (id)valueForKey:(NSString *)key;
- (id)valueForKeyPath:(NSString *)keyPath;
- (NSDictionary *)dictionaryWithValuesForKeys:(NSArray *)keys;
- (NSMutableArray *)mutableArrayValueForKey:(NSString *)key;
- (NSMutableArray *)mutableArrayValueForKeyPath:(NSString *)keyPath;
- (NSMutableSet *)mutableSetValueForKey:(NSString *)key;
- (NSMutableSet *)mutableSetValueForKeyPath:(NSString *)keyPath;

在属性(名为myKey)中搜索值时,Apple 的文档声明valueForKey:搜索如下:

  1. 在接收器内部尝试-getMyKey-myKey-isMyKey(按顺序)
  2. 如果没有找到,它会尝试这些有序的、对多的 g​​etter(NSArray):

    // Required:
    - (NSUInteger)countOfMyKey;
    
    // Requires At Least One:
    - (id)objectInMyKeyAtIndex:(NSUInteger)index;
    - (NSArray *)myKeyAtIndexes:(NSIndexSet *)indexes;
    
    // Optional (improves performance):
    - (void)getMyKey:(KeyClass **)buffer range:(NSRange)inRange;
    
  3. 接下来,它会尝试这些无序的、对多的 g​​etter(NSSet):

    - (NSUInteger)countOfMyKey;
    - (NSEnumerator *)enumeratorOfMyKey;
    - (KeyClass *)memberOfMyKey:(KeyClass *)anObject;
    
  4. 接下来,它尝试直接访问实例变量,假设YESaccessInstanceVariablesDirectly,按以下顺序返回:_myKey_isMyKeymyKeyisMyKey

  5. 最后,它放弃并调用接收类的- (id)valueForUndefinedKey:(NSString *)key方法。通常这里会引发错误。


我的问题是,mutableArrayValueForKey: 的搜索顺序模式是什么?

苹果的文档说明了这一点

有序集合的访问者搜索模式

mutableArrayValueForKey: 的默认搜索模式如下:

在接收者的类中搜索名称匹配模式 -insertObject:inAtIndex: 和 -removeObjectFromAtIndex: 的一对方法(分别对应于 NSMutableArray 原始方法 insertObject:atIndex: 和 removeObjectAtIndex:),或匹配模式 -insert:atIndexes 的方法: 和 -removeAtIndexes: (对应于 NSMutableArrayinsertObjects:atIndexes: 和 removeObjectsAtIndexes: 方法)。如果找到至少一种插入方法和至少一种删除方法,则发送到集合代理对象的每个 NSMutableArray 消息将导致 -insertObject:inAtIndex:、-removeObjectFromAtIndex:、-insert:atIndexes: 和 -removeAtIndexes: 消息的某种组合被发送到 mutableArrayValueForKey: 的原始接收者。...ETC...

这对我来说毫无意义,因为它正在讨论类似“setter”的方法。 mutableArrayValueForKey:返回一个 NSMutableArray。上面列出的所有方法都返回 void,并用于编辑 NSMutableArray,而不是获取它。例子:

- (void)insertMyKey:(KeyClass *)keyObject inMyKeyAtIndex:(NSUInteger)index;
- (void)removeObjectFromMyKeyAtIndex:(NSUInteger)index;

知道 Apple 在他们的文档中试图说什么,或者这可能是一个错误吗?

我的理论是,这可能会采用与搜索检索 KVC 值时mutableArrayValueForKey:类似的路径。valueForKey:我只是不确定那真的是什么路径。

谢谢你尽你所能的帮助!:)

4

1 回答 1

23

NSMutableArray您从调用中返回的mutableArrayValueForKey:实际上是一个私有子类,NSMutableArray它覆盖了普通数组方法,例如-count-objectAtIndex:-insertObject:atIndex:等,并在从中检索数组的对象上调用相应的 KVC 方法。它基本上充当了操纵对象的多对多关系的代理,您不必担心自己创建或返回。一个简单的用法示例:

Playlist* aPlaylist;
Track* aTrack;
NSMutableArray* mutableTracks = [aPlaylist mutableArrayValueForKey:@"tracks"];
[mutableTracks insertObject:aTrack atIndex:0];

这段代码将曲目添加到播放列表的开头。如果 Playlist 类为其“轨道”关系实现 KVC 方法,则在可变数组上调用方法将导致在底层对象上调用适当的方法。因此,在本例中,当您调用insertObject:atIndex:数组时,数组将依次调用insertObjectInTracks:atIndex:播放列表对象,并将曲目添加到播放列表的曲目数组中。

现在,在这个例子中,你当然可以直接调用,但是你可以不使用它来代替insertObjectInTracks:atIndex:它有几个好处。mutableArrayValueForKey:

  • 数组包装器隐藏了底层 KVC 方法的实现细节。实现整个方法列表并不严格要求符合 KVC。Playlist 类可以只实现-tracksand -setTracks:,上面的代码仍然可以工作。在这种情况下,可变数组代理不会调用 ,而是insertObjectInTracks:atIndex:创建一个新数组,并在开头插入对象,然后只调用setTracks:Playlist 对象。这显然效率较低,因此通常建议实施完整的 KVC 方法列表。
  • 在这种情况下,不是键的常量字符串,而是一个变量,使用mutableArrayValueForKey:允许您操纵关系,而不必知道您必须调用的方法的确切名称。只要对象与您使用的密钥的 KVC 兼容,一切都会“正常工作”。
  • 它还允许您使用NSMutableArray本身实现的任何方法,例如,您可以使用在数组中搜索对象、对数组进行排序等方法,而无需重写特殊版本来处理 KVC 内容。
于 2010-02-19T07:33:08.090 回答