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