美文网首页iOS Dev
iOS使用自定义对象作为NSDictionary的key探索

iOS使用自定义对象作为NSDictionary的key探索

作者: 码农二哥 | 来源:发表于2017-03-03 13:36 被阅读1575次

从不喜欢搞优雅高调的官方开场白,多数都是直接上代码!
根据苹果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.

References

相关文章

网友评论

    本文标题:iOS使用自定义对象作为NSDictionary的key探索

    本文链接:https://www.haomeiwen.com/subject/xholgttx.html