Як ви правильно перекриваєте isEqual:
в Objective-C? «Улов» здається таким, що якщо два об’єкти рівні (як визначено isEqual:
методом), вони повинні мати однакове хеш-значення.
У розділі інтроспекції Посібника з основ какао є приклад того, як перекрити isEqual:
, скопійований так, для класу з назвою MyWidget
:
- (BOOL)isEqual:(id)other {
if (other == self)
return YES;
if (!other || ![other isKindOfClass:[self class]])
return NO;
return [self isEqualToWidget:other];
}
- (BOOL)isEqualToWidget:(MyWidget *)aWidget {
if (self == aWidget)
return YES;
if (![(id)[self name] isEqual:[aWidget name]])
return NO;
if (![[self data] isEqualToData:[aWidget data]])
return NO;
return YES;
}
Він перевіряє рівність вказівника, потім рівність класу, і, нарешті, порівнює об'єкти, використовуючи isEqualToWidget:
, що тільки перевіряє name
і data
властивості. Приклад не показує, як перекрити hash
.
Припустимо, є й інші властивості, які не впливають на рівність, скажімо age
. Чи не варто hash
метод бути перевизначений таким чином, що тільки name
і data
впливають на хеш? І якщо так, то як би ви це зробили? Просто додайте хеші name
та data
? Наприклад:
- (NSUInteger)hash {
NSUInteger hash = 0;
hash += [[self name] hash];
hash += [[self data] hash];
return hash;
}
Це достатньо? Чи є краща техніка? Що робити, якщо у вас є примітиви, як int
? Перетворити їх, щоб NSNumber
отримати хеш? Або конструкції як NSRect
?
( Мозговий пердець : Спочатку написав "побіжно АБО" їх разом із |=
. Має на увазі.)
if (![other isKindOfClass:[self class]])
- Це технічно означає, що рівність не буде комунальною. Тобто A = B не означає B = A (наприклад, якщо один є підкласом іншого)