Как вы правильно переопределяете isEqual: в Objective-C? Кажется, что "улов" состоит в том, что если два объекта равны (как определено методом isEqual:), они должны иметь одинаковое значение хэширования.
Раздел Introspection в Cocoa Руководство по основам имеет пример того, как переопределить 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?
( Brain fart: Изначально он писал "побитовое ИЛИ" вместе с |=. Meant add.)