【问题标题】:How to effectively use NSMutableDictionaries as keys for a dictionary?如何有效地使用 NSMutableDictionaries 作为字典的键?
【发布时间】:2013-02-21 18:32:01
【问题描述】:

我想使用NSMutableDictionary 实例作为另一个NSMutableDictionary 的键。

    NSMutableDictionary *stuff = [NSMutableDictionary dictionary];
    NSMutableDictionary *first = [NSMutableDictionary dictionary];
    [stuff setObject:@"A" forKey:first];
    NSLog(@"I GOT %@",[stuff objectForKey:first]);

这会按预期输出@"A",这很好。

但是,如果之后我像这样修改first 对象中的值:

[first setObject:@"C" forKey:@"Something"];

我现在无法获取@"A"

NSLog(@"I GOT %@",[stuff objectForKey:first]);

哪个输出nil

我假设objectForKey 会将键的内存地址与字典中的现有键进行比较 - 因为尽管更改了字典的内部值(我认为),但这样的内存地址不会改变,我预计它会起作用。

我设法让它使用不同的方法 - 改为使用 NSStrings 作为键 - 字符串的值将是内存地址本身,如下所示:

    NSMutableDictionary *stuff = [NSMutableDictionary dictionary];
    NSMutableDictionary *first = [NSMutableDictionary dictionary];
    [stuff setObject:@"A" forKey:[NSString stringWithFormat:@"%p",first]];
    [first setObject:@"C" forKey:@"Something"];
    NSLog(@"I GOT %@",[NSString stringWithFormat:@"%p",first]);

哪个有效,打印@"A"

我的问题:

  • 为什么我原来的方法不起作用?

【问题讨论】:

    标签: ios objective-c nsdictionary nsmutabledictionary


    【解决方案1】:

    字典在设置时获取其键的副本(并且该副本是不可变的)。然后,当您更改用于密钥的对象时,它和副本不再比较相等:NSDictionary 在检查密钥时使用 hashisEqual:。 (集合在这些方法中不使用对象的地址来确定它们是否相等,即使它们相等,副本和原始地址也不同。)因此您无法检索该值。如果您将字典重新变异为原来的样子,则检索将成功。

    你想出的字符串技巧是一个很好的解决方法;您也可以为此目的使用+[NSValue valueWithNonRetainedObject:]。因为键字典的地址在你mutate时并没有改变,你仍然可以得到相同的值来查找。

    【讨论】:

    • 我明白了,但是内存地址会一直保持不变?
    • 副本的内存地址和原密钥相同。
    • 事实上,copy 的定义意味着在内存中的新位置创建了一个新对象。
    • @Omega:因为对象的地址在你mutate时不会改变。
    • 我明白了。谢谢,帮了大忙!
    【解决方案2】:

    我假设 objectForKey 会将键的内存地址与字典中现有的键进行比较

    在多个级别上都错了。

    如果键是通过内存地址进行比较的,那么就没有切实可行的方法来获取键的对象。如果您使用常量字符串@"Foo" 作为键,并且在运行时,您传递了另一个NSString 实例,其内容为Foo,但它是一个不同的对象(因此它的内存地址完全不同)?

    所以没有。而objectForKey: 所做的是将isEqual: 消息发送到键以确定它们是否相等。默认情况下,此方法在NSObject 中实现,它确实比较内存地址,但它在大多数对其有意义的标准集合类中被覆盖(对于NSStringNSNumberNSArrayNSDictionary,等等),并且它进行了语义上更正确、内容相关的比较。

    此外,NSDicionary 的键在设置键-对象对时复制。这意味着如果使用直接指针比较,根本无法获取任何对象,因为副本是不同的对象,是对象的另一个实际实例,指针指向的对象其他地方(显然)。 (旁注:对于一些不可变的 Cocoa 类,例如 NSString,这并不完全正确,其中 copy 本质上是使用 retain 实现的,但您应该了解这个概念。

    【讨论】:

      猜你喜欢
      • 2017-11-02
      • 1970-01-01
      • 2011-08-20
      • 2021-09-22
      • 2012-09-06
      • 2021-05-07
      • 2019-01-17
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多