Як ви правильно перекриваєте 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 (наприклад, якщо один є підкласом іншого)