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