How do you properly override isEqual:
in Objective-C? The “catch” seems to be that if two objects are equal (as determined by the isEqual:
method), they must have the same hash value.
The Introspection section of the Cocoa Fundamentals Guide does have an example on how to override isEqual:
, copied as follows, for a class named 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;
}
It checks pointer equality, then class equality, and finally compares the objects using isEqualToWidget:
, which only checks the name
and data
properties. What the example doesn’t show is how to override hash
.
Let’s assume there are other properties that do not affect equality, say age
. Shouldn’t the hash
method be overridden such that only name
and data
affect the hash? And if so, how would you do that? Just add the hashes of name
and data
? For example:
- (NSUInteger)hash {
NSUInteger hash = 0;
hash += [[self name] hash];
hash += [[self data] hash];
return hash;
}
Is that sufficient? Is there a better technique? What if you have primitives, like int
? Convert them to NSNumber
to get their hash? Or structs like NSRect
?
(Brain fart: Originally wrote “bitwise OR” them together with |=
. Meant add.)