Подтвердить что ты не робот

Cocoa NSDictionary: почему ключи скопированы?

Все объекты, используемые в качестве ключей в словарях NS (Mutable), должны поддерживать протокол NSCopying, и эти объекты копируются, когда они используются в словаре.

Я часто хочу использовать более тяжелые весовые объекты в качестве ключей, просто чтобы сопоставить один объект с другим. Что я действительно имею в виду, когда я делаю это эффективно:

[dictionary setObject:someObject forKey:[NSValue valueWithPointer:keyObject]];

( "Когда я вернусь и снова отправлю вам этот тот же экземпляр ключевого объекта, получите мне то же значение".)

... Именно это я и делаю, чтобы иногда обойти этот дизайн. (Да, я знаю о NSMapTable на рабочем столе Cocoa, но, например, iPhone не поддерживает это.)

Но я действительно не понимаю, почему копирование ключа необходимо или желательно в первую очередь. Что он покупает для реализации или вызывающего?

4b9b3361

Ответ 1

Копия гарантирует, что значения, используемые в качестве ключей, не меняются "underhand" при использовании в качестве ключей. Рассмотрим пример изменяемой строки:

NSMutableString* key = ... 
NSMutableDictionary* dict = [[NSMutableDictionary alloc] init];

[dict setObject: ... forKey: key];

Предположим, что словарь не скопировал ключ, а вместо этого просто retain отредактировал его. Если теперь, в какой-то более поздней момент, исходная строка будет изменена, то очень вероятно, что вы не собираетесь снова найти свое сохраненное значение в словаре, даже если вы используете тот же самый ключевой объект (т.е. Один key указывает в примере выше).

Чтобы защитить себя от такой ошибки, словарь копирует все ключи.

Обратите внимание, что, кстати, достаточно просто определить -copyWithZone: как просто выполнение return [self retain]. Это допустимо и хороший код, если ваш объект неизменен, а контракт NSCopying специально разработан таким образом, что возвращаемый объект должен быть (sorta, kinda) неизменным:

Реализовать NSCopying, сохранив оригинал вместо создания новой копии, когда класс и его содержимое являются неизменяемыми.

(из Справка NSCopying)

и

Возвращенная копия является неизменной, если рассмотрение вопроса о "неизменяемом и изменяемом" относится к принимающему объекту; в противном случае точный характер копии определяется классом.

(из - copyWithZone: Ссылка)

Даже если ваши объекты не являются неизменными, вы можете уйти с этой реализацией, если только когда-либо используете реализации равенства/хэша на основе идентификации, то есть реализации, которые никак не затрагиваются внутренним состоянием объекта.

Ответ 2

Если вы хотите сохранить указатели в виде ключей, вам необходимо обернуть их в объект NSValue с помощью +valueWithPointer:.

Ответ 3

Так как iOS 6, если вы хотите использовать указатели в качестве ключей, вы можете использовать объект NSMapTable, см. http://nshipster.com/nshashtable-and-nsmaptable/

Вы можете указать, являются ли ключи и/или значения жестко или слабо удерживаются:

NSMapTable *mapTable = [NSMapTable mapTableWithKeyOptions:NSMapTableStrongMemory
                                         valueOptions:NSMapTableWeakMemory];

Другим вариантом, который может быть уместным, является использование NSCache, который содержит ключи сильно и фактически является потокобезопасным.