子类化 MKAnnotation 导致 Set 集合不起作用
Subclassing MKAnnotation cause Set collection doesn’t work
我刚刚发现 MKAnnotation
类型的 Set
没有按预期工作。
class MyAnnotation: MKPointAnnotation {
let id: String
init(_ id: String) {
self.id = id
}
override var hash: Int {
return id.hash
}
static func ==(lhs: MyAnnotation, rhs: MyAnnotation) -> Bool {
return lhs.hashValue == rhs.hashValue
}
}
let m1 = MyAnnotation("1")
let m2 = MyAnnotation("2")
let n1 = MyAnnotation("1")
let n2 = MyAnnotation("2")
m1.hashValue //918
n1.hashValue //918
m2.hashValue //921
n2.hashValue //921
if m1 == n1 && m2 == n2 {
print(true)
}
// prints true
let s1 = Set(arrayLiteral: m1, m2)
let s2 = Set(arrayLiteral: n1, n2)
let i = s1.intersection(s2)
// empty
即使哈希相同,m 和 n 的交集也是空的。请与下面的示例进行比较:
class MyAnnotation: Hashable, Equatable {
let id: String
init(_ id: String) {
self.id = id
}
var hashValue: Int {
return id.hash
}
static func ==(lhs: MyAnnotation, rhs: MyAnnotation) -> Bool {
return lhs.hashValue == rhs.hashValue
}
}
let m1 = MyAnnotation("1")
let m2 = MyAnnotation("2")
let n1 = MyAnnotation("1")
let n2 = MyAnnotation("2")
m1.hashValue //918
n1.hashValue //918
m2.hashValue //921
n2.hashValue //921
if m1 == n1 && m2 == n2 {
print(true)
}
// prints true
let s1 = Set(arrayLiteral: m1, m2)
let s2 = Set(arrayLiteral: n1, n2)
let i = s1.intersection(s2)
// {{id "1"}, {id "2"}}
m 和 n 的交集符合预期。
是不是很奇怪?可能中间有什么我不知道也不明白的地方。
Xcode 10.1
在第一个代码中,您没有使用 Equatable 协议,但在第二个代码中您使用了 Equatable 协议,因此它可以正常工作。
Equatable协议用于比较。您可以参考下面link了解更多信息:
https://useyourloaf.com/blog/swift-equatable-and-comparable/
解决方法是覆盖isEqual(_ object: Any?) -> Bool
.
因为MKAnnotation
是从NSObject
派生出来的,所以我们需要重写NS的方法。如果我们深入研究实现 (^
+ ⌘
),我们会发现:
Subclasses of NSObject
can customize Equatable conformance by overriding isEqual(_:)
. If two objects are equal, they must have the same hash value, so if you override isEqual(_:)
, make sure you also override the hash
property.
我刚刚发现 MKAnnotation
类型的 Set
没有按预期工作。
class MyAnnotation: MKPointAnnotation {
let id: String
init(_ id: String) {
self.id = id
}
override var hash: Int {
return id.hash
}
static func ==(lhs: MyAnnotation, rhs: MyAnnotation) -> Bool {
return lhs.hashValue == rhs.hashValue
}
}
let m1 = MyAnnotation("1")
let m2 = MyAnnotation("2")
let n1 = MyAnnotation("1")
let n2 = MyAnnotation("2")
m1.hashValue //918
n1.hashValue //918
m2.hashValue //921
n2.hashValue //921
if m1 == n1 && m2 == n2 {
print(true)
}
// prints true
let s1 = Set(arrayLiteral: m1, m2)
let s2 = Set(arrayLiteral: n1, n2)
let i = s1.intersection(s2)
// empty
即使哈希相同,m 和 n 的交集也是空的。请与下面的示例进行比较:
class MyAnnotation: Hashable, Equatable {
let id: String
init(_ id: String) {
self.id = id
}
var hashValue: Int {
return id.hash
}
static func ==(lhs: MyAnnotation, rhs: MyAnnotation) -> Bool {
return lhs.hashValue == rhs.hashValue
}
}
let m1 = MyAnnotation("1")
let m2 = MyAnnotation("2")
let n1 = MyAnnotation("1")
let n2 = MyAnnotation("2")
m1.hashValue //918
n1.hashValue //918
m2.hashValue //921
n2.hashValue //921
if m1 == n1 && m2 == n2 {
print(true)
}
// prints true
let s1 = Set(arrayLiteral: m1, m2)
let s2 = Set(arrayLiteral: n1, n2)
let i = s1.intersection(s2)
// {{id "1"}, {id "2"}}
m 和 n 的交集符合预期。
是不是很奇怪?可能中间有什么我不知道也不明白的地方。
Xcode 10.1
在第一个代码中,您没有使用 Equatable 协议,但在第二个代码中您使用了 Equatable 协议,因此它可以正常工作。
Equatable协议用于比较。您可以参考下面link了解更多信息:
https://useyourloaf.com/blog/swift-equatable-and-comparable/
解决方法是覆盖isEqual(_ object: Any?) -> Bool
.
因为MKAnnotation
是从NSObject
派生出来的,所以我们需要重写NS的方法。如果我们深入研究实现 (^
+ ⌘
),我们会发现:
Subclasses of
NSObject
can customize Equatable conformance by overridingisEqual(_:)
. If two objects are equal, they must have the same hash value, so if you overrideisEqual(_:)
, make sure you also override thehash
property.