这个SO answer表明NSDictionary的哈希值是字典中的条目数。 (Similarly, the hash of an NSArray is its length。)答案继续建议创建一个类别以提供更好的哈希实现。
如果您需要更准确的哈希值,可以提供一个哈希值 你自己在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'”。
现在,如果我在类别标头和实现文件中将方法从散列重命名为hashy(例如),则[dict hashy]
将返回正确的值。是否无法覆盖类别中的“内置”方法?我做错了吗?
答案 0 :(得分:10)
NSDictionary是一个类集群 - 当您向NSDictionary发送消息时,您与之交互的内容绝不是NSDictionary的实际实例,而是私有子类的实例。因此,当您覆盖类别中的hash
方法时,它确实覆盖了NSDictionary中的该方法,但具体的子类有自己的hash
方法,因此它会覆盖您的。{/ p>
如果你真的想这样做,我想你会想要检查NSDictionaryI和NSDictionaryM类的存在,并动态覆盖它们的hash
方法。但这是内部实现细节的混乱,我不建议这样做,除非你真的陷入困境。如果您分析并查找NSDictionary的hash
方法是个问题,我会尝试创建一个包装NSDictionary的类,但在使用私有实现类之前提供自己的自定义hash
方法 - 实现类可以在没有警告的情况下改变(以及之前),所以任何依赖它们的设计都是脆弱的。