【问题标题】:Implementing an NSOutlineView to edit the contents of a plist file实现 NSOutlineView 来编辑 plist 文件的内容
【发布时间】:2010-11-02 19:44:42
【问题描述】:

我正在使用 cocos2d-iphone 编写游戏,我们的阶段在 .plist 文件中定义。但是,文件越来越大 - 所以我开发了一个编辑器,它为流程添加了一些结构,并将大部分 plist 分解为固定字段。但是,某些元素仍然需要 plist 编辑器类型功能,因此我在显示“其他参数”的面板上实现了 NSOutlineView。我正在尝试从 XCode 的“属性列表编辑器”复制功能。

我已经实现了以下系统; http://www.stupendous.net/archives/2009/01/11/nsoutlineview-example/

这非常接近我的需要,但是我今天大部分时间都在尝试解决一个问题。通过查找父字典并使用,从所选项目“向后”计算键列的值;

return [[parentObject allKeysForObject:item] objectAtIndex:0];

但是,当树中的给定字典中有多个具有相同值的项目时,此语句总是返回具有该值的第一个项目(它似乎使用 isEqualToString: 或哈希值比较字符串)。这导致键列显示“item1, item1, item1”而不是 item1, item2, item3(其中项目 1-3 都具有值“”)。我接下来尝试了;

-(NSString*)keyFromDictionary:(NSDictionary*)dict forItem:(id)item
{
for( uint i = 0; i < [[dict allKeys] count]; i++ ) {
    id object = [dict objectForKey:[[dict allKeys] objectAtIndex:i]];

    if ( &object == &item ) {
        return [[dict allKeys] objectAtIndex:i];
    }
}   

return nil;
}

但这总是返回 nil。我希望对 NSOutlineView 有更多经验的人能够提供更好的解决方案。虽然这个问题在链接的例子中只出现过一次,但在从字典中删除项目时,我不得不多次使用它。任何帮助将不胜感激。

【问题讨论】:

    标签: objective-c cocoa plist nsoutlineview


    【解决方案1】:
    return [[parentObject allKeysForObject:item] objectAtIndex:0];
    

    但是,当树中给定字典中有多个具有相同值的项目时,此语句始终返回具有该值的第一个项目......

    嗯,是的。这就是你告诉它要做的事情:“给我这个值的所有键;给我数组中的第一项;退回那个”。

    ...此语句始终返回具有该值的第一个项目(它似乎使用 isEqualToString: 或哈希值比较字符串)。

    不是那个声明在做它;这就是字典的工作原理:每个键只能在字典中出现一次,并且只能有一个对象作为其值,这是使用键的散列并通过发送键 isEqual: 消息(不是特定于 NSString isEqualToString:——键不需要是字符串*)。

    另一方面,这些值不是唯一的。任意数量的键可以具有相同的值。这就是为什么从值到键——尤其是到 a 键——如此成问题的原因。

    *无论如何,不​​在 NSDictionary 中。当您尝试生成 plist 输出时,如果字典包含任何非字符串键,它将失败。

    我接下来尝试了;

    -(NSString*)keyFromDictionary:(NSDictionary*)dict forItem:(id)item
    {
        for( uint i = 0; i < [[dict allKeys] count]; i++ ) {
            id object = [dict objectForKey:[[dict allKeys] objectAtIndex:i]];
    
            if ( &object == &item ) {
                return [[dict allKeys] objectAtIndex:i];
            }
        }   
    
        return nil;
    }
    

    但这总是返回 nil。

    这是代码中最少的问题。

    首先,在对 NSArray 进行迭代时,除非绝对需要,否则通常不应使用索引。使用fast enumeration更干净。

    其次,当您确实需要 NSArray 的索引时,正确的类型是 NSUInteger。尽量不要混搭类型。

    第三,我不知道你对那里的地址操作符是什么意思,但你实际上做的是获取这两个变量的地址。因此,您比较了局部变量 object 是否与参数变量 item 相同。由于它们不是同一个变量,因此该测试始终返回 false,这就是为什么您永远不会返回对象的原因——唯一的另一个退出点返回 nil,所以这总是会发生的。

    这段代码和前面的单行代码的问题在于,您试图从一个值转到单个键,这与字典的工作方式相反:只有键是唯一的;任意数量的键都可以具有相同的值。

    您需要使用其他东西作为物品。使用钥匙作为物品是一种方法;用model object 代表每一行将是另一行。

    如果你走模型-对象路线,不要忘记防止同一个虚拟字典中的多行具有相同的键。 NSMutableSet 加上实现 hashisEqual: 将对此有所帮助。

    您可能还应该对数组的处理进行相同的更改。

    【讨论】:

    • 感谢代码提示 - 因为这是一个仅供内部使用的内部项目,我已经偷工减料了一点 - 但快速枚举看起来很棒。
    • 我遇到的主要问题是 NSOutlineView 在它的委托函数中为您提供了一个项目(不是行号/索引路径)。因此,找出该值的字典键是有问题的,但对于更新是必要的。我想我可以将 NSoutlineView 传递给它的代表的项目的内存地址与 Dictionary 中项目的地址进行比较 - 但我猜其中一个项目正在“复制”对象,因此地址永远不会匹配。我想我必须将大纲视图的所有项目从 plist 格式转换为自定义对象,然后再保存...
    • John Wordsworth:NSDictionaries 复制他们的密钥。他们通过(1)比较它们的哈希值和(2)询问它们是否彼此相等来测试键的相等性;您应该以相同的方式比较键。
    【解决方案2】:

    为了澄清,我最终通过为 plist 文件中的每个集合创建代理对象来解决这个问题(因此,对于每个 NSMutableArray 或 NSMutableDictionary)。这意味着我基本上镜像了 Plist 结构,并在每个级别包含了对原始对象的引用。这允许我存储每个对象的数组索引或字典键,因此当将项目从大纲视图保存回 Plist 结构时,我使用了代理对象的“键”或“索引”属性。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-01-13
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多