【问题标题】:ObjectIdentifier needed for Swift equality?Swift 相等需要 ObjectIdentifier?
【发布时间】:2017-05-27 10:09:54
【问题描述】:

我们有一个自定义 Swift 类的多个实例,它继承自 SKSpriteNode,并且能够正确执行以下代码(对于这个问题进行了大幅简化):

let instance1 = CustomClass()
let instance2 = CustomClass()
let instance3 = CustomClass()
let instance4 = CustomClass()

let array1 = [instance1, instance2]
let array2 = [instance3, instance4]

func check(testInstance: CustomClass) -> Bool {
   return array1.filter({ $0 == testInstance }).count > 0
}

check(testInstance: instance3)

换句话说,执行check(testInstance: instance3) 按预期返回false

但是,我们进行了大量更改,check 停止工作。

CustomClass 没有实现Equatable 协议。我们只想检测唯一的实例。

它是在我们使用ObjectIdentifier 时才开始工作的,这意味着函数变成了这样:

func check(testInstance: CustomClass) -> Bool {
   return array1.filter({ ObjectIdentifier($0) == ObjectIdentifier(testInstance) }).count > 0
}

为什么需要ObjectIdentifier,什么时候应该使用它来实现对象相等?

这是用 Swift 3 编写的。

【问题讨论】:

  • 基本上是===,看这个:stackoverflow.com/questions/39587027/…
  • @Hamish 身份比较,不找属性比较
  • @Crashalot 所以它继承自NSObject?如果您命令单击== 运算符,Xcode 将带您到被调用的重载。
  • @Crashalot 然后继承自NSObject :) 所以isEqual(_:) 的实现很可能是你需要寻找的地方。
  • @Hamish 是的,刚刚按照您的建议进行了命令单击,似乎使用了来自NSObject== 函数。

标签: ios swift skspritenode sknode


【解决方案1】:

为什么需要ObjectIdentifier,什么时候应该使用它来实现对象相等?

在这种情况下,您不需要使用ObjectIdentifier 来执行身份比较,您可以简单地使用身份运算符=== 代替Martin says here,对于类实例相当于使用@ 987654331@的==过载:

func check(testInstance: CustomClass) -> Bool {
    return array1.contains(where: { $0 === testInstance })
}

还请注意,我们使用 contains(where:) 而不是 filter{...}.count > 0,因为前者会在找到匹配元素时短路,而后者会评估整个序列(并创建一个不必要的中间数组)。

直接使用== 来执行对象的身份比较可能有效,因为CustomClass 最终继承自NSObject,它通过定义符合Equatable an == overload 调用 isEqual(_:),默认情况下执行身份比较。

但是一般来说,这应该被依赖——isEqual(_:) 的实现可以被覆盖以基于属性值而不是身份来执行比较。此外,语义上Equatable 要求== 的实现完全基于被比较实例的可见方面(即属性值)。

来自the documentation

平等意味着可替代性——任何两个比较的实例 同样可以在任何依赖于它们的代码中互换使用 价值观。为了保持可替代性,== 运算符应考虑 说明Equatable 类型的所有可见方面。

因此,使用== 对您的班级进行身份比较永远不会正确,即使它最初可能有效。

至于什么时候应该使用ObjectIdentifier,你真的不应该需要它只是来进行身份比较。对于类,您应该使用=== 运算符,对于元类型,您应该简单地使用专门为它们定义的== 重载(在这种情况下,标识恰好是相等的,因为每个新的元类型实例都是唯一的)。

ObjectIdentifier 的主要用途实际上是它的hashValue 实现,它派生自初始化对象的指针值。这可能很有用,例如,允许元类型为 Dictionary 键(比较 Make a Swift dictionary where the key is "Type"?)。

【讨论】:

  • 这么棒的回应,希望我能给你10倍的积分:)
  • contains Swift 3 的新手吗?有人建议之前使用filter,但也许那是在contains 存在之前?再次感谢!
  • @Crashalot 乐于助人!而contains 从 Swift 1 时代就已经存在 :) 虽然当时它是一个顶级函数——它在 Swift 2 中成为Sequence(Type) 的实例方法。
  • 该死的你和你的 23K 点知识!你拿走了使用filter 而不是contains 的唯一好借口!现在剩下的就是“糟糕的开发者”哈哈哈。 :) 再次感谢!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-07-31
  • 2019-07-10
  • 1970-01-01
相关资源
最近更新 更多