Swift平等需要ObjectIdentifier吗?

我们有一个自定义的Swift类的实例,它inheritance自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写的。

为什么需要ObjectIdentifier ,什么时候用于对象平等?

在这种情况下,您不需要使用ObjectIdentifier来执行标识比较,您可以简单地使用标识符运算符=== ,正如Martin在这里所说的 ,对于类实例而言,它等同于使用ObjectIdentifier “过载” :

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

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

直接使用==来执行对象的标识比较可能是有效的,因为CustomClass最终从NSObjectinheritance, NSObject通过定义调用isEqual(_:)==重载符合Equatable ,默认情况下执行身份比较。

然而,一般来说,这应该依赖 – isEqual(_:)的实现可以被重写,以基于属性值而非身份执行比较。 此外,在语义上, Equatable要求==的实现基于所有正在比较的实例的可见方面(即属性值)。

从文档 :

平等意味着可替代性 – 平等比较的任何两个实例可以在任何取决于其值的代码中互换使用。 为了保持可替代性, ==运算符应该考虑到Equatabletypes的所有可见方面。

因此,使用==作为类的身份比较是不正确的,即使它最初可能起作用。

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

ObjectIdentifier的主要用途是它的hashValue实现,它是从它初始化的东西的指针值派生而来的。 例如,在允许元types是Dictionary键(比较Make一个Swift字典,键是“Type”? )的情况下,这是很有用的。