【问题标题】:Subclassing MKAnnotation cause Set collection doesn’t work子类化 MKAnnotation 导致 Set 集合不起作用
【发布时间】:2019-04-15 12:49:35
【问题描述】:

我刚刚发现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

【问题讨论】:

  • 你错过了第一部分的 Hashable
  • @Sh_Khan MKAnnotation 默认符合EquatableHashable

标签: ios swift inheritance set mapkit


【解决方案1】:

在第一个代码中,您没有使用 Equatable 协议,但在第二个代码中您使用了 Equatable 协议,因此它可以正常工作。

Equatable 协议用于比较。您可以参考以下链接了解更多信息:

https://useyourloaf.com/blog/swift-equatable-and-comparable/

【讨论】:

  • 但是MKPointAnnotation符合Equatable和Hashable。
【解决方案2】:

解决方案是覆盖isEqual(_ object: Any?) -> Bool

因为MKAnnotation 派生自NSObject 我们需要重写NS 的方法。如果我们深入研究实现 (^ + ),我们会发现:

NSObject 的子类可以通过覆盖 isEqual(_:) 来自定义 Equatable 一致性。如果两个对象相等,则它们必须具有相同的哈希值,因此如果您覆盖 isEqual(_:),请确保您还覆盖了 hash 属性。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-02-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-04-26
    • 2020-09-18
    • 2022-08-11
    相关资源
    最近更新 更多