从不喜欢搞优雅高调的官方开场白,多数都是直接上代码!
根据苹果API的文档来看:The key for value. The key is copied (using copyWithZone:; keys must conform to the NSCopying protocol). If aKey already exists in the dictionary, anObject takes its place.
OK,直接看代码:
@interface WKeyCustom : NSObject<NSCopying>
@property (nonatomic, strong) NSString *name;
@end
@implementation WKeyCustom
//这样做之后,就可以当作key传到NSDictionary中去了
-(id)copyWithZone:(NSZone *)zone
{
WKeyCustom *aCopy = [[WKeyCustom allocWithZone:zone] init];
if(aCopy)
{
[aCopy setName:[self.name copyWithZone:zone]];
}
return aCopy;
}
@end
- (void)doHashTest
{
WKeyCustom *keyCustomA = [[WKeyCustom alloc] init];
keyCustomA.name = @"keyA";
WKeyCustom *keyCustomB = [[WKeyCustom alloc] init];
keyCustomB.name = @"keyA";
NSMutableDictionary *mdict = [[NSMutableDictionary alloc] init];
[mdict setObject:@"keyA" forKey:keyCustomA];
[mdict setObject:@"keyB" forKey:keyCustomB];
NSLog(@"%@", mdict);//这里输出啥???--(1)
NSString *str = [mdict objectForKey:keyCustomA];
NSLog(@"%@", str);//这里输出啥???--(2)
}
答案:
(1)//难到不该是只有一个对象么?至少期望是只有一个对象的。
{
"<WKeyCustom: 0x618000019860>" = keyB;
"<WKeyCustom: 0x618000019a80>" = keyA;
}
(2)//只实现了copyWithZone,只能保证放的进去,却没办法取出来
(null)
--------华丽的分割线-----------
如果我给WKeyCustom
类增加一个isEqual方法呢,会不会是我们预期的结果呢?
- (BOOL)isEqual:(id)object
{
if ([object isKindOfClass:self.class] && [((WKeyCustom *)object).name isEqualToString:self.name])
{
return YES;
}
return NO;
}
你才刚才的输出结果是什么?
答案:
{
"<WKeyCustom: 0x618000208b70>" = keyA;
"<WKeyCustom: 0x618000208b90>" = (null);//这是什么鬼?
}
2017-03-03 13:00:47.416 WiOSDemo[63915:1211904] (null)
这个结果很出乎意料吧,难到你猜对是这样了?好吧,其实mdict的内容是不一定的,多次运行试试,每次运行的结果可能都不太一样,至少在我们的电脑上是这样的。其实这是一个错误的设计,这种做法的结果是undefined。
--------华丽的分割线-----------
我们再给我们的WKeyCustom
增加一个方法,让它实现我们预期的效果:
-(NSUInteger)hash
{
return self.name.hash;
}
结果:
2017-03-03 13:26:33.103 WiOSDemo[64063:1227637] {
"<WKeyCustom: 0x608000016260>" = keyB;
}
2017-03-03 13:26:33.104 WiOSDemo[64063:1227637] keyB
总结
- 只要key遵循NSCoping协议,它确实可以放到NSDictionary里面
- 你不实现isEqual:和hash方法也不会出错,因为NSObject实现了
- 当且仅当两个对象类型相同且你认为相等(这种相等由你决定)时, isEqual:才返回YES
- 如果isEqual:返回YES,那么hash也必须返回YES;
On the other hand, it is ok to occasionally have different objects with the same hash value, although it’s better if you minimize how often this happens.