This SO answerは、NSDictionary のハッシュが辞書内のエントリの数であることを示しています。(同様に、NSArray のハッシュはその長さです。)答えは、より良いハッシュ実装を提供するためにカテゴリを作成することを提案します。
より正確なハッシュ値が必要な場合は、Obj-C カテゴリで自分で提供できます。
しかし、これを試してみると、とにかく元のハッシュ実装を使用しているようです。
ヘッダーがありますNSDictionary+Hash.h
#import <Foundation/Foundation.h>
@interface NSDictionary (Hash)
- (NSUInteger)hash;
@end
そして実装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;
}
簡単な単体テストは、元の実装が使用されていることを示しています。
#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
このテストは、「'2' は '2949297985' と等しくなければなりません」で失敗します。
ここで、カテゴリ ヘッダーと実装ファイルでメソッドの名前を hash から hashy (たとえば) に変更すると[dict hashy]
、正しい値が返されます。カテゴリの「組み込み」メソッドをオーバーライドすることはできませんか? 私は他に何か間違ったことをしていますか?