在Swift中继承NSObject时,你应该覆盖哈希还是实现Hashable?另外,你应该覆盖isEqual:或者实现==?
答案 0 :(得分:86)
NSObject
已符合Hashable
协议:
extension NSObject : Equatable, Hashable {
/// The hash value.
///
/// **Axiom:** `x == y` implies `x.hashValue == y.hashValue`
///
/// - Note: the hash value is not guaranteed to be stable across
/// different invocations of the same program. Do not persist the
/// hash value across program runs.
public var hashValue: Int { get }
}
public func ==(lhs: NSObject, rhs: NSObject) -> Bool
我找不到官方参考资料,但似乎hashValue
从hash
调用NSObjectProtocol
方法,==
调用
isEqual:
方法(来自同一协议)。 请参阅更新
答案结束了!
对于NSObject
子类,似乎是正确的方法
覆盖hash
和isEqual:
,这是一个实验
证明:
hashValue
和==
class ClassA : NSObject {
let value : Int
init(value : Int) {
self.value = value
super.init()
}
override var hashValue : Int {
return value
}
}
func ==(lhs: ClassA, rhs: ClassA) -> Bool {
return lhs.value == rhs.value
}
现在创建两个不同的类实例 "等于"并将它们放入一套:
let a1 = ClassA(value: 13)
let a2 = ClassA(value: 13)
let nsSetA = NSSet(objects: a1, a2)
let swSetA = Set([a1, a2])
print(nsSetA.count) // 2
print(swSetA.count) // 2
如您所见,NSSet
和Set
都将对象视为不同。
这不是理想的结果。阵列也有意想不到的结果:
let nsArrayA = NSArray(object: a1)
let swArrayA = [a1]
print(nsArrayA.indexOfObject(a2)) // 9223372036854775807 == NSNotFound
print(swArrayA.indexOf(a2)) // nil
设置断点或添加调试输出显示被覆盖
永远不会调用==
运算符。我不知道这是一个bug还是
预期的行为。
hash
和isEqual:
class ClassB : NSObject {
let value : Int
init(value : Int) {
self.value = value
super.init()
}
override var hash : Int {
return value
}
override func isEqual(object: AnyObject?) -> Bool {
if let other = object as? ClassB {
return self.value == other.value
} else {
return false
}
}
}
对于 Swift 3,,isEqual:
的定义已更改为
override func isEqual(_ object: Any?) -> Bool { ... }
现在所有结果都符合预期:
let b1 = ClassB(value: 13)
let b2 = ClassB(value: 13)
let nsSetB = NSSet(objects: b1, b2)
let swSetB = Set([b1, b2])
print(swSetB.count) // 1
print(nsSetB.count) // 1
let nsArrayB = NSArray(object: b1)
let swArrayB = [b1]
print(nsArrayB.indexOfObject(b2)) // 0
print(swArrayB.indexOf(b2)) // Optional(0)
更新:现在记录了此行为 Interacting with Objective-C APIs 在"使用Swift与Cocoa和Objective-C"参考:
NSObject类只执行身份比较,因此您应该在从NSObject类派生的类中实现自己的isEqual:方法。
作为实现类的相等性的一部分,请确保根据Object比较中的规则实现hash属性。
答案 1 :(得分:1)
对于 NSObject
,最好覆盖 hash
和 isEqual
。它已经符合 Hashable
和 Equatable
,并且已经合成了依次调用 hash
和 isEqual
的一致性。因此,由于它是一个 NSObject
,因此请使用 ObjC 方式并覆盖也会影响 ObjC 哈希值和相等性的值。
class Identity: NSObject {
let name: String
let email: String
init(name: String, email: String) {
self.name = name
self.email = email
}
override var hash: Int {
var hasher = Hasher()
hasher.combine(name)
hasher.combine(email)
return hasher.finalize()
}
override func isEqual(_ object: Any?) -> Bool {
guard let other = object as? Identity else {
return false
}
return name == other.name && email == other.email
}
}
答案 2 :(得分:0)
实施Hashable
,这也要求您为您的类型实施==
运算符。这些用于Swift标准库中的许多有用的东西,例如indexOf
函数,它只适用于实现Equatable
的类型的集合,或仅适用于Set<T>
类型的Hashable
类型实现=query(A2:D20, "select A, MAX(C) GROUP BY A pivot B",1)
的类型。