【问题标题】:What is the KVC Search Pattern for mutableArrayValueForKey?mutableArrayValueForKey 的 KVC 搜索模式是什么?
【发布时间】:2016-05-30 21:57:42
【问题描述】:

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

下面我将解释我是如何理解valueForKey: KVC“getters”工作的。然后我会回答关于 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: 的搜索顺序模式是什么?

Apple's docs state this:

有序的访问器搜索模式 收藏

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

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

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

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

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

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

感谢您提供的任何帮助! :)

【问题讨论】:

    标签: cocoa nsmutablearray key-value-coding


    【解决方案1】:

    调用mutableArrayValueForKey:返回的NSMutableArray实际上是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 类可以只实现-tracks-setTracks:,上面的代码仍然可以工作。在这种情况下,可变数组代理不会调用insertObjectInTracks:atIndex:,而是会在开头插入对象创建一个新数组,然后只需在播放列表对象上调用setTracks:。这显然效率较低,因此通常建议实施完整的 KVC 方法列表。
    • 如果您有一个变量,而不是键的常量字符串,则使用mutableArrayValueForKey: 允许您操纵关系,而不必知道您必须调用的方法的确切名称。只要对象与您使用的密钥的 KVC 兼容,一切都会“正常工作”。
    • 它还允许您使用NSMutableArray 本身实现的任何方法,例如,您可以使用在数组中搜索对象、对数组进行排序等方法,而无需重写特殊版本来处理 KVC 内容。

    【讨论】:

    • 谢谢布赖恩,这非常有帮助。 :)
    • “这段代码在播放列表的开头添加了一个曲目”,我认为它在曲目的开头添加了一个曲目,而不是播放列表?
    • 说这种方法在使用绑定时是相关的。在上面的例子中,如果 Playlist 是一个绑定到轨道数组的 NSArrayController 并且我们有一个 NSTableView 绑定到这个控制器,那么为了通过数组控制器将轨道上的更改反映到表中,我们必须从可变的轨道中获取轨道数组代理,然后在此轨道上添加/删除对象:实际上这些操作将反映到将触发绑定机制的 KVC 命令。
    • 为什么不谈谈房间里的大象呢?这整件事是为了支持 Cocoa 绑定而创建的。如果您有一个 NSTableView 绑定到 NSArrayController ,而其内容(模型)绑定到一个普通的 NSMutableArray - 改变模型数组(即插入/删除项目)将不会反映在 UI 中,因为 NSMutableArray 不符合 KVC/KVO。但是,如果您使用 mutableArrayValueForKey: 代理并绑定到该代理 - 一切都像魅力一样。这些“符合 KVC 的可变数组”代理的效率远低于普通数组,但对于 UI,它们是完美的
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-02-26
    • 2010-10-17
    • 2010-12-14
    • 1970-01-01
    • 1970-01-01
    • 2013-05-25
    • 1970-01-01
    相关资源
    最近更新 更多