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
最终从NSObject
inheritance, NSObject
通过定义调用isEqual(_:)
的==
重载符合Equatable
,默认情况下执行身份比较。
然而,一般来说,这不应该依赖 – isEqual(_:)
的实现可以被重写,以基于属性值而非身份执行比较。 此外,在语义上, Equatable
要求==
的实现基于所有正在比较的实例的可见方面(即属性值)。
从文档 :
平等意味着可替代性 – 平等比较的任何两个实例可以在任何取决于其值的代码中互换使用。 为了保持可替代性,
==
运算符应该考虑到Equatable
types的所有可见方面。
因此,使用==
作为类的身份比较是不正确的,即使它最初可能起作用。
至于什么时候应该使用ObjectIdentifier
,真的不应该只是为了执行一个身份比较。 对于类,您应该使用===
运算符,对于元types,您应该简单地使用专门为它们定义的==
重载(因为在这种情况下,身份恰好相等,因为每个新的元types实例都是唯一的)。
ObjectIdentifier
的主要用途是它的hashValue
实现,它是从它初始化的东西的指针值派生而来的。 例如,在允许元types是Dictionary
键(比较Make一个Swift字典,键是“Type”? )的情况下,这是很有用的。