This SO answer shows that the hash of an NSDictionary is the number of entries in the dictionary. (Similarly, the hash of an NSArray is its length.) The answer goes on to suggest creating a category to provide a better hash implementation.
If you need to have a more accurate hash value, you can provide one yourself in an Obj-C category.
But when I try this, it appears to use the original hash implementation anyway.
We have the header in NSDictionary+Hash.h
#import <Foundation/Foundation.h>
@interface NSDictionary (Hash)
- (NSUInteger)hash;
@end
And the implementation in NSDictionary+Hash.m
:
#import "NSDictionary+Hash.h"
@implementation NSDictionary (Hash)
- (NSUInteger)hash
{
// Based upon standard hash algorithm ~ https://stackoverflow.com/a/4393493/337735
NSUInteger result = 1;
NSUInteger prime = 31;
// Fast enumeration has an unstable ordering, so explicitly sort the keys
// https://stackoverflow.com/a/8529761/337735
for (id key in [[self allKeys] sortedArrayUsingSelector:@selector(compare:)]) {
id value = [self objectForKey:key];
// okay, so copying Java's hashCode a bit:
// http://docs.oracle.com/javase/6/docs/api/java/util/Map.Entry.html#hashCode()
result = prime * result + ([key hash] ^ [value hash]);
}
return result;
}
A simple unit test shows the original implementation is in use:
#import "NSDictionary+Hash.h"
#import <SenTestingKit/SenTestingKit.h>
@interface NSDictionary_HashTest : SenTestCase
@end
@implementation NSDictionary_HashTest
- (void)testHash
{
NSDictionary *dict = [NSDictionary dictionaryWithObjectsAndKeys:
@"val1", @"key1", @"val2", @"key2", nil];
NSUInteger result = 1;
result = 31 * result + ([@"key1" hash] ^ [@"val1" hash]);
result = 31 * result + ([@"key2" hash] ^ [@"val2" hash]);
STAssertEquals([dict hash], result, nil);
}
@end
This test fails with "'2' should be equal to '2949297985'".
Now, if I rename the method from hash to hashy (for example) in the category header and implementation files, then [dict hashy]
returns the correct value. Is it not possible to override a "built-in" method in a category? Am I doing something else wrong?