Ответ на этот вопрос и ключ к предотвращению многих ошибок какао:
Внимательно прочитайте документацию. Поместите каждое слово и пунктуацию в золотую шкалу и взвесьте, как это было последнее зерно пшеницы в мире.
Давайте снова прочитаем документацию:
Если изменяемый объект добавлен в коллекцию, которая использует хеш-значения для определения позиции объекта в коллекции, [...]
(выделено мое).
Что автор документации, в своей вечной мудрости, подразумевает под этим то, что когда вы реализуете коллекцию, например словарь, вы не должны использовать хеш для позиционирования, поскольку это может измениться. Другими словами, это не имеет ничего общего с реализацией -hash на изменчивых объектах Какао (что все мы думали, что это имело место, предполагая, что документация не изменилась за последние ~ 10 лет, с тех пор как был задан вопрос).
Именно поэтому словари всегда копируют свои ключи - чтобы они могли гарантировать
что значение хеша не изменится.
Затем вы зададите вопрос: Но, сэр, как NSMapTable и подобные ему справляются с этим?
Ответ на это согласно документации:
"Его ключи или значения могут быть скопированы на вход или может использовать идентичность указателя для равенства и хэширования."
(снова выделение мое).
Поскольку в прошлый раз нас так легко одурачила документация, давайте проведем небольшой эксперимент, чтобы убедиться, как на самом деле все работает:
NSMutableString *string = [NSMutableString stringWithString:@"so lets mutate this"];
NSString *originalString = string.copy;
NSMapTable *mutableStrings = [NSMapTable strongToStrongObjectsMapTable];
[mutableStrings setObject:originalString forKey:string];
[string appendString:@" into a larger string"];
if ([mutableStrings objectForKey:string] == nil)
NSLog(@"not found!");
if ([mutableStrings objectForKey:originalString] == nil)
NSLog(@"Not even the original string is found?");
for (NSString *inCollection in mutableStrings)
{
NSLog(@"key '%@' : is '%@' (null)", inCollection, [mutableStrings objectForKey:inCollection]);
}
for (NSString *value in NSAllMapTableValues(mutableStrings))
{
NSLog(@"value exists: %@", value);
}
Сюрприз!
Таким образом, вместо использования указателя равенства они сосредотачиваются на словах «может», которые в данном случае означают «не может», и просто копируют значение хеша при добавлении содержимого в коллекцию.
(Все это на самом деле хорошо, так как было бы довольно сложно реализовать NSHashMap или -hash, в противном случае).