ios - NSSet containsObject 错误结果
问题描述
我正在写一个类似于糖果迷恋的游戏。我有一个“交换”类型来表示交换 2 个 cookie。
@interface Cookie : NSObject {
}
@property (strong) Coord2D *coord;
@end
@implementation Cookie {
}
@interface Swap : NSObject {
}
@property (strong) Cookie *cookieA;
@property (strong) Cookie *cookieB;
@end
@implementation Swap
- (BOOL)isEqual:(id)object {
Swap *other = object;
return ([_cookieA.coord isEqual:other.cookieA.coord] && [_cookieB.coord isEqual:other.cookieB.coord])
|| ([_cookieA.coord isEqual:other.cookieB.coord] && [_cookieB.coord isEqual:other.cookieA.coord]);
}
- (NSUInteger)hash {
// (A, B) and (B, A) must be interchangable (hash to the same value)
return (_cookieA.coord.row + _cookieB.coord.row) ^ (_cookieA.coord.col + _cookieB.coord.col);
}
- (NSString *)description
{
return [NSString stringWithFormat:@"[%@, %@]", _cookieA.coord, _cookieB.coord];
}
@end
而 the被简单地cookie.coord
定义为一个类型Coord2D
row
col
@interface Coord2D : NSObject {
}
@property int row;
@property int col;
@end
@implement Coord2D
- (BOOL)isEqual:(id)object {
Coord2D *other = object;
return _row == other.row && _col == other.col;
}
- (NSUInteger)hash {
return _row ^ _col;
}
- (NSString *)description
{
return [NSString stringWithFormat:@"(%i, %i)", _row, _col];
}
@end
现在我需要测试一个 NSSet 是否allPossibleSwaps
包含一个新创建的swap
对象。
(lldb) po allPossibleSwaps
{(
[(2, 4), (2, 5)],
[(1, 1), (2, 1)],
[(1, 0), (2, 0)],
[(2, 4), (2, 3)],
[(1, 2), (2, 2)],
[(0, 4), (1, 4)],
[(1, 4), (2, 4)],
[(1, 4), (1, 5)],
[(2, 3), (2, 4)]
)}
(lldb) po swap
[(1, 4), (2, 4)]
(lldb) p [allPossibleSwaps containsObject:swap]
(bool) $64 = false
结果应该是肯定的,但实际上是否定的。
这里有几个线索:
containsObject: (allObject[6] is wrong!) 同样奇怪的是它们被打印为true/false
而不是YES/NO
(lldb) p [allPossibleSwaps containsObject: allPossibleSwaps.allObjects[0]]
(bool) $41 = true
(lldb) p [allPossibleSwaps containsObject: allPossibleSwaps.allObjects[1]]
(bool) $40 = true
(lldb) p [allPossibleSwaps containsObject: allPossibleSwaps.allObjects[2]]
(bool) $42 = true
(lldb) p [allPossibleSwaps containsObject: allPossibleSwaps.allObjects[3]]
(bool) $39 = true
(lldb) p [allPossibleSwaps containsObject: allPossibleSwaps.allObjects[4]]
(bool) $43 = true
(lldb) p [allPossibleSwaps containsObject: allPossibleSwaps.allObjects[5]]
(bool) $44 = true
(lldb) p [allPossibleSwaps containsObject: allPossibleSwaps.allObjects[6]]
(bool) $45 = false
(lldb) p [allPossibleSwaps containsObject: allPossibleSwaps.allObjects[7]]
(bool) $46 = true
(lldb) p [allPossibleSwaps containsObject: allPossibleSwaps.allObjects[8]]
(bool) $47 = true
isEqual 调用(似乎正确)
(lldb) p [(Swap *)(allPossibleSwaps.allObjects[0]) isEqual:swap]
(BOOL) $53 = NO
(lldb) p [(Swap *)(allPossibleSwaps.allObjects[1]) isEqual:swap]
(BOOL) $52 = NO
(lldb) p [(Swap *)(allPossibleSwaps.allObjects[2]) isEqual:swap]
(BOOL) $54 = NO
(lldb) p [(Swap *)(allPossibleSwaps.allObjects[3]) isEqual:swap]
(BOOL) $55 = NO
(lldb) p [(Swap *)(allPossibleSwaps.allObjects[4]) isEqual:swap]
(BOOL) $56 = NO
(lldb) p [(Swap *)(allPossibleSwaps.allObjects[5]) isEqual:swap]
(BOOL) $57 = NO
(lldb) p [(Swap *)(allPossibleSwaps.allObjects[6]) isEqual:swap]
(BOOL) $50 = YES
(lldb) p [(Swap *)(allPossibleSwaps.allObjects[7]) isEqual:swap]
(BOOL) $51 = NO
(lldb) p [(Swap *)(allPossibleSwaps.allObjects[8]) isEqual:swap]
(BOOL) $58 = NO
哈希调用:(似乎正确)
(lldb) p ((Swap *)allPossibleSwaps.allObjects[0]).hash
(NSUInteger) $30 = 13
(lldb) p ((Swap *)allPossibleSwaps.allObjects[1]).hash
(NSUInteger) $31 = 1
(lldb) p ((Swap *)allPossibleSwaps.allObjects[2]).hash
(NSUInteger) $32 = 3
(lldb) p ((Swap *)allPossibleSwaps.allObjects[3]).hash
(NSUInteger) $33 = 3
(lldb) p ((Swap *)allPossibleSwaps.allObjects[4]).hash
(NSUInteger) $34 = 7
(lldb) p ((Swap *)allPossibleSwaps.allObjects[5]).hash
(NSUInteger) $35 = 9
(lldb) p ((Swap *)allPossibleSwaps.allObjects[6]).hash
(NSUInteger) $36 = 11
(lldb) p ((Swap *)allPossibleSwaps.allObjects[7]).hash
(NSUInteger) $37 = 11
(lldb) p ((Swap *)allPossibleSwaps.allObjects[8]).hash
(NSUInteger) $65 = 3
(lldb) p swap.hash
(NSUInteger) $66 = 11
解决方案
您的散列和 isEquals 逻辑看起来是正确的。从您的控制台输出判断,哈希值和 isEquals 的行为都符合预期。因此,在重新散列期间,项目很可能被放入错误的桶中。
当您从集合中插入或删除项目时,会发生重新散列。如果您不熟悉散列的工作原理,这里有一篇很好的文章:https ://en.wikipedia.org/wiki/Extendible_hashing
是否有可能您的 cookie 交换逻辑弄乱了集合中已经存在的 Swap 项目?您是否在插入后修改坐标?
推荐阅读
- github - 如何使用 github api 来决定两个提交之间的依赖关系?
- c# - EventWaitHandle waitOne() 导致我的工作线程暂停,直到它超时
- javascript - 使用 HTML SSE 获取数据库记录更新通知
- azure - 具有跨国复制的 Azure 托管实例故障转移
- python - Sendgrid Python 回复电子邮件
- rust - 如果文件更短,如何读取文件的前 N 个字节或更短?
- docker - 为什么在为 HyperLedgerFabric 安装 Fabric 示例和二进制文件时出现“无法连接到 docker daemon”错误?
- ionic-framework - 从 IONIC 中的模态控制器获取数据
- java - 如何为内部带有“this”的方法编写Junit测试
- javascript - eval() 后无法访问函数