在 Swift 中继承 NSObject 时,您应该覆盖哈希还是实现 Hashable?另外,你应该覆盖 isEqual: 还是实现 ==?
最佳答案
NSObject
已经符合 Hashable
协议(protocol):
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:
方法(来自同一协议(protocol))。 见更新答案结束!
对于
NSObject
子类,正确的方法似乎是覆盖
hash
和 isEqual:
,这是一个实验证明:
1. 覆盖
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还是预期的行为。
2. 覆盖
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)
更新: 该行为记录在“使用 Swift 与 Cocoa 和 Objective-C”一书中的“与 Objective-C API 交互”下:
这本书可在 Apple Book 应用程序中找到。
它也记录在 Apple 的网站上,但已被删除,并且在页面的 WebArchive snapshot 上仍然可见。
关于swift - Swift 中的 NSObject 子类 : hash vs hashValue, isEqual vs ==,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/33319959/