在Swift中继承NSObject时,你应该覆盖哈希还是实现Hashable?另外,你应该覆盖isEqual:或者实现==?
Mar*_*n R 94
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
Run Code Online (Sandbox Code Playgroud)
我找不到官方参考,但它似乎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
}
Run Code Online (Sandbox Code Playgroud)
现在创建两个不同的类实例,它们被认为是"相等的"并将它们放入一个集合中:
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
Run Code Online (Sandbox Code Playgroud)
正如你所看到的,NSSet并且Set治疗的对象不同.这不是理想的结果.数组也有意想不到的结果:
let nsArrayA = NSArray(object: a1)
let swArrayA = [a1]
print(nsArrayA.indexOfObject(a2)) // 9223372036854775807 == NSNotFound
print(swArrayA.indexOf(a2)) // nil
Run Code Online (Sandbox Code Playgroud)
设置断点或添加调试输出会显示==从不调用重写的
运算符.我不知道这是一个错误或预期的行为.
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
}
}
}
Run Code Online (Sandbox Code Playgroud)
对于Swift 3,定义isEqual:改为
override func isEqual(_ object: Any?) -> Bool { ... }
Run Code Online (Sandbox Code Playgroud)
现在所有结果都符合预期:
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)
Run Code Online (Sandbox Code Playgroud)
更新:现在在 "使用Swift with Cocoa和Objective-C"参考中与Objective-C API交互中记录了该行为 :
NSObject类只执行身份比较,因此您应该在派生自NSObject类的类中实现自己的isEqual:方法.
作为实现类的相等性的一部分,请确保根据Object比较中的规则实现hash属性.
小智 10
因为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
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
10406 次 |
| 最近记录: |