HashBuilder
Creating custom data objects as subclasses of NSObject is something which tends to happen
quite often, and making those objects “good citizens” which can be reliably placed into
NS collections (NSDictionary
, NSSet
, NSArray
, etc.) means taking a few extra steps.
One of these steps is to override NSObject
’s - (BOOL)isEqual:(id)object
method, and,
of course if you do that, you should (read: must) also override - (NSUInteger)hash
.
Providing a good hash value from your overridden - (NSUInteger)hash
method is a deep
topic, luckily we can stand on the backs of giants, and use knowledge and techniques
which follow “known good” practices. With that in mind, I created a utility, HashBuilder,
which makes generating a suitable hash value trivial.
HashBuilder can be used to build a hash
result from contributed objects or hashes (presumably properties on your object which
should be considered in the isEqual: override). The intention is for the hash result to be
returned from an override to the NSObject
- (NSUInteger)hash
method.
Documentation
To use, create a HashBuilder object, contribute to it, then query the ‘builtHash’ property for the resulting hash.
- (NSUInteger)hash
{
HashBuilder *builder = [HashBuilder builder];
[builder contributeObject:self.objectID];
[builder contributeObject:self.occurredDate];
[builder contributeObject:self.type];
[builder contributeObject:self.objectURL];
[builder contributeObject:self.tags];
[builder contributeObject:self.count];
NSUInteger retVal = builder.builtHash;
return retVal;
}
It is prudent to consider the same properties when overriding your - (BOOL)isEqual:(id)object
method as well.
NOTE: The order of contribution will change the resulting hash, even if all the same values are contributed. For example:
HashBuilder *builder1 = [HashBuilder builder];
[builder1 contributeObject:@"a"];
[builder1 contributeObject:[NSNumber numberWithInteger:12345]];
NSUInteger hash1 = builder1.builtHash;
HashBuilder *builder2 = [HashBuilder builder];
[builder2 contributeObject:[NSNumber numberWithInteger:12345]];
[builder2 contributeObject:@"a"];
NSUInteger hash2 = builder2.builtHash;
hash1 != hash2
Installing
If you’re using CocoPods it’s as simple as adding this to your Podfile
:
pod 'HashBuilder', '~> 1.0'
NOTE: HashBuilder makes use of techniques and concepts presented by Mike Ash in his post entitled Implementing Equality and Hashing