【发布时间】:2018-10-24 12:26:42
【问题描述】:
我创建了一个采用Hashable 协议的类。
所以我创建了这个类的一些具有不同属性的实例并将它们添加到集合中。
然后我改变一个对象的属性。
在此更改之后,Set 有时会失败 .contains(还有 .remove)。
在调试器检查器中,我看到该对象与 Set 中的元素具有相同的内存地址。那么为什么会随机失败呢?
请注意,我总能找到集合内元素的索引。
我在 Playground(在 xcode10 上)进行了多次测试,每次执行结果都会发生变化。
class Test: Hashable {
// MARK: Equatable protocol
static func == (lhs: Test, rhs: Test) -> Bool {
return lhs === rhs || lhs.hashValue == rhs.hashValue
}
var s: String
func hash(into hasher: inout Hasher) {
hasher.combine(s.hashValue)
}
init(s: String) {
self.s = s
}
}
func test(s: Set<Test>, u: Test) -> Bool {
if s.contains(u) {
print("OK")
return true
} else {
print("FAIL") // SOMETIMES FAIL
if !s.contains(u) {
if let _ = s.firstIndex(where: { $0 == u }) {
print("- OK index") // ALWAYS OK
return true
} else {
print("- FAIL index") // NEVER FAIL
return false
}
} else {
return true
}
}
}
var s: Set<Test> = []
let u1 = Test(s: "a")
s.insert(u1)
let u2 = Test(s: "b")
s.insert(u2)
test(s: s, u: u2)
u2.s = "c"
test(s: s, u: u2)
u2.s = "d"
test(s: s, u: u2)
u2.s = "b"
test(s: s, u: u2)
【问题讨论】:
-
为什么在
else子句中使用嵌套的if !s.contains(u)?你能解释一下你想达到什么目的吗/ -
对不起,嵌套的if是错误的,但不影响问题
-
可能与stackoverflow.com/questions/28461675/…重复,经过必要的修改后
-
一种解决方法可能是:将哈希存储在私有属性
private var _hash:Int?中,并且在hashValue中只存储一次:var hashValue: Int { if (_hash == nil) { _hash = s.hashValue }; return _hash! }(为了线程安全,使用 GCDonce东西)跨度>