Что такое функция NSObject isEqual: и хэш по умолчанию?

У меня есть класс модели базы данных, который является NSObject. У меня есть набор этих объектов в файле NSMutableArray. Я использую indexOfObject:, чтобы найти совпадение. Проблема заключается в изменении адреса памяти объекта модели. Поэтому я переопределяю метод hash, чтобы вернуть идентификатор строки модели. Однако это не исправляет ситуацию. Я также должен переопределить метод isEqual:, чтобы сравнить значение метода hash.

Что использует метод isEqual: для определения равенства по умолчанию?

Я предполагаю, что он использует адрес памяти. После прочтения isEqual: Я думал, что она использует значение из метода hash. Очевидно, это не так, поскольку моя попытка переопределить это значение не решила мою первоначальную проблему.


person Brenden    schedule 06.08.2009    source источник
comment
Здесь есть несколько спекулятивных ответов. Может ли кто-нибудь предоставить фактическую документацию о том, что isEquals по умолчанию использует адрес › Я не утверждаю, что это не так, просто хотел бы услышать это из первых уст.   -  person DougW    schedule 26.08.2011
comment
@DougW Я разделил ваши чувства по этому поводу, поэтому я нашел официальную ссылку и отредактировал ее в принятом ответе.   -  person Mark Amery    schedule 28.08.2013
comment
Вы читаете документацию по протоколу NSObject, а не по классу NSObject. Протокол определяет, что должны делать методы, класс не может определить, что он на самом деле делает. Всегда безопаснее переопределять равенства и хеш, чтобы они работали так, как вы хотите.   -  person Terry Wilcox    schedule 28.08.2013
comment
@TerryWilcox Нет, это задокументировано, как указано в принятом ответе. Это просто не задокументировано в справочнике по классам, где вы этого ожидаете. Совершенно не обязательно переопределять isEqual: для выполнения явного сравнения указателей с == только для того, чтобы безопасно передать indexOfObject: экземпляр некоторого произвольного подкласса NSObject - вы можете быть уверены, что isEqual: NSObject выполнит сравнение указателей.   -  person Mark Amery    schedule 28.08.2013
comment
@MarkAmery Я имел в виду, что это не задокументировано в документации класса, где это должно быть задокументировано. Однострочное упоминание в другом документе является документацией случайно. И хотя вы можете быть уверены, что NSObject будет обеспечивать равенство указателей, полагать, что равенства указателей всегда достаточно, несколько рискованно.   -  person Terry Wilcox    schedule 28.08.2013
comment
@TerryWilcox Я согласен, что документация по этому вопросу ужасно плохая, но я думаю, что предложение всегда переопределять isEqual: и не доверять реализации NSObject заходит слишком далеко. Очевидно, однако, что если равенство указателей (что проверяет реализация NSObject isEqual:) на самом деле не является тем, что вам нужно, то вы должны переопределить его.   -  person Mark Amery    schedule 28.08.2013
comment
@MarkAmery Я не говорил, что вы не можете доверять методу equals NSObject, я сказал, что безопаснее всегда переопределять его, чтобы делать то, что вы хотите. Это похоже на сравнение первичных ключей в объекте базы данных, вместо того, чтобы надеяться, что ваш постоянный уровень кэширует ваши объекты настолько хорошо, что никогда не подумает, что ему нужно перезагрузить данные. Вы можете скрестить пальцы или быть откровенным. Один безопаснее другого.   -  person Terry Wilcox    schedule 28.08.2013


Ответы (3)


Как вы правильно догадались, поведение NSObject по умолчанию isEqual: сравнивает адрес памяти объекта. Как ни странно, в настоящее время это не задокументировано в Справочник по классу NSObject, но он задокументирован в Интроспекция, в которой говорится:

Реализация NSObject по умолчанию для isEqual: просто проверяет равенство указателей.

Конечно, как вы, несомненно, знаете, подклассы NSObject могут переопределять isEqual:, чтобы вести себя по-другому. Например, метод isEqual: NSString при передаче другого NSString сначала проверит адрес, а затем проверит точное буквальное совпадение между строками.

person Kenny Winker    schedule 23.11.2010
comment
Ссылка на это была бы хороша. - person Mark Amery; 27.08.2013
comment
... поэтому я добавил один. Как ни странно, в справочнике по классу NSObject нет даже записи для isEqual:, не говоря уже о описании его поведения где-либо, что кажется вопиющим упущением. Однако мне удалось найти официальную ссылку на какой-то малоизвестной странице в «концептуальном» разделе документов. - person Mark Amery; 28.08.2013
comment
Документация Apple изобилует случаями, когда методы протокола не описаны в документации по классам. (Не говоря уже о методах суперкласса.) Вам часто приходится копаться под кучей камней, чтобы найти документацию для данного метода. - person Hot Licks; 28.08.2013
comment
(Мне бы хотелось, чтобы документация Apple была больше похожа на документацию Java, где все унаследованные методы, по крайней мере, перечислены с описанием класса.) - person Hot Licks; 28.08.2013

Ответ о реализации isEqual: по умолчанию является исчерпывающим. Поэтому я просто добавляю свое примечание о реализации hash по умолчанию. Вот:

-(unsigned)hash {return (unsigned)self;}

То есть это точно такое же значение указателя, которое используется в isEqual:. Вот как вы можете это проверить:

NSObject *obj = [[NSObject alloc] init];
NSLog(@"obj: %@",obj);
NSLog(@"hash: %x",obj.hash);

Результат будет примерно таким:

obj: <NSObject: 0x16d44010>
hash: 16d44010

С уважением.

Кстати, в iOS 8 hash стало свойством, а не методом, но оно есть.

person ilnar_al    schedule 01.10.2014

Я бы предположил, что NSObject isEquals использует оператор ==, а hash использует адрес памяти.

Метод isEquals никогда не должен использовать hash в качестве абсолютного теста на равенство. Гарантировано, что два объекта имеют одинаковые hashCode, если вы ищете достаточное количество объектов (просто создайте более 2^32 разных объектов, и по крайней мере два из них будут иметь одинаковые hash).

Другими словами, hash требует следующей спецификации: если два объекта равны, то их hash должно быть равно; однако, если значения hash двух объектов равны, они не обязательно равны.

В качестве подсказки вы всегда должны переопределять isEquals и hashCode вместе.

person notnoop    schedule 06.08.2009