这SO answer显示 NSDictionary 的哈希是字典中的条目数。 ( Similarly, the hash of an NSArray is its length 。)答案继续建议创建一个类别以提供更好的哈希实现。
If you need to have a more accurate hash value, you can provide one yourself in an Obj-C category.
但是当我尝试这样做时,它似乎仍然使用原始哈希实现。
我们在 NSDictionary+Hash.h
中有 header
#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’”。
现在,如果我在类别 header 和实现文件中将方法从 hash 重命名为 hashy(例如),则 [dict hashy]
会返回正确的值。无法覆盖类别中的“内置”方法吗?我做错了什么吗?
最佳答案
NSDictionary 是一个类簇——当您向 NSDictionary 发送消息时,您与之交互的永远不是 NSDictionary 的实际实例,而是私有(private)子类的实例。所以当你重写类别中的 hash
方法时,它确实重写了 NSDictionary 中的那个方法,但是具体的子类有它自己的 hash
方法,所以它重写了你的方法。
如果您真的想这样做,我认为您需要检查类 NSDictionaryI 和 NSDictionaryM 是否存在并动态覆盖它们的 hash
方法。但这在内部实现细节上是乱七八糟的,我不建议这样做,除非你在某种程度上真的陷入了困境。如果您分析并发现 NSDictionary 的 hash
方法有问题,我会尝试创建一个包装 NSDictionary 但提供其自己的自定义 hash
方法的类,然后再处理私有(private)实现类 — 实现类可以在没有警告的情况下更改(并且之前已经更改),因此任何依赖它们的设计都是脆弱的。
关于objective-c - 覆盖 NSArray 的哈希值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14696922/