Ios 如何有效地使用NSMutableDictionary作为字典的键?

Ios 如何有效地使用NSMutableDictionary作为字典的键?,ios,objective-c,nsdictionary,nsmutabledictionary,Ios,Objective C,Nsdictionary,Nsmutabledictionary,我想使用NSMutableDictionary实例作为另一个NSMutableDictionary的键 正如预期的那样,这会输出@A,这很好 但是,如果之后我修改第一个对象中的值,如下所示: [first setObject:@"C" forKey:@"Something"]; NSMutableDictionary *stuff = [NSMutableDictionary dictionary]; NSMutableDictionary *first = [NSMutabl

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

正如预期的那样,这会输出@A,这很好

但是,如果之后我修改第一个对象中的值,如下所示:

[first setObject:@"C" forKey:@"Something"];
    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:

输出为零

我假设objectForKey会将键的内存地址与字典中现有的键进行比较——因为尽管更改了字典的内部值,但这样的内存地址不会更改,我想,我希望它会工作

我设法用一种不同的方法使它工作—通过使用NSStrings作为键—字符串的值将是内存地址本身,如下所示:

[first setObject:@"C" forKey:@"Something"];
    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

我的问题:

为什么我最初的方法不起作用?
字典在设置它的键时会获取它的一个副本,并且该副本是不可变的。然后,当您对用于密钥的对象进行变异时,它与副本的比较不再相等:NSDictionary在检查密钥时使用hash和isEqual:。在这些方法中,集合不使用对象的地址来决定它们是否相等,即使相等,副本和原始副本也有不同的地址。因此,您无法检索该值。如果你把字典改成原来的样子,检索就会成功


你想出的弦乐技巧是一个很好的解决方法;为此,您还可以使用+[NSValue valueWithNonRetainedObject:]。由于密钥字典的地址在您仅对其进行变异时不会发生更改,因此您仍然可以获得相同的值以供以后查找。

当设置密钥时,字典会获取其密钥的副本,并且该副本是不可变的。然后,当您对用于密钥的对象进行变异时,它与副本的比较不再相等:NSDictionary在检查密钥时使用hash和isEqual:。在这些方法中,集合不使用对象的地址来决定它们是否相等,即使相等,副本和原始副本也有不同的地址。因此,您无法检索该值。如果你把字典改成原来的样子,检索就会成功

你想出的弦乐技巧是一个很好的解决方法;为此,您还可以使用+[NSValue valueWithNonRetainedObject:]。由于密钥字典的地址在您仅对其进行变异时不会发生更改,因此您仍然可以获得相同的值以供以后查找

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

在多个层面上都是错误的

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

所以没有。objectForKey:所做的是将isEqual:消息发送给键,以确定它们是否相等。默认情况下,此方法在NSObject中插入,它确实会比较内存地址,但在大多数标准集合类中它会被重写,对于这些标准集合类,NSString、NSNumber、NSArray、NSDictionary等都是合理的。它会进行语义上更正确的、与内容相关的比较

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

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

在多个层面上都是错误的

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

所以没有。objectForKey:所做的是将isEqual:消息发送给键,以确定它们是否相等。默认情况下,此方法在NSObject中插入,它确实会比较内存地址,但在大多数标准集合类中它会被重写,对于这些标准集合类,NSString、NSNumber、NSArray、NSDictionary等都是合理的。它会进行语义上更正确的、与内容相关的比较

此外,当设置密钥对象对时,会复制NSDicionary的密钥。这意味着,如果使用直接指针比较,将根本无法获取任何对象,因为副本是另一个对象,即指针指向的对象的另一个实际实例
很明显,他要去别的地方。旁注:对于某些不可变的Cocoa类,如NSString,这并不完全正确,其中copy基本上是使用retain实现的,但您应该了解这个概念。

,但内存地址将始终保持不变?副本和原始密钥的内存地址不相同。事实上,副本的定义意味着在内存中的新位置创建一个新对象。@Omega:因为对象的地址在变异时不会改变。我明白了。谢谢,这帮了大忙!我明白了,但内存地址将始终保持不变?副本和原始密钥的内存地址不相同。事实上,副本的定义意味着在内存中的新位置创建一个新对象。@Omega:因为对象的地址在您对其进行变异时不会改变。我明白了。谢谢,这帮了大忙!