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