Swift中的NSObject子类:hash vs hashValue,isEqual vs ==

在Swift中对NSObject进行子类化时,应该覆盖哈希还是实现Hashable?另外,你应该覆盖isEqual:还是实现==?
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
从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还是
意图行为。

2.覆盖哈希和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与可可和Objective-C”参考:

The NSObject class only performs an identity comparison,so you should implement your own isEqual: method in classes that derive from the NSObject class.

As part of implementing equality for your class,be sure to implement the hash property according to the rules in Object comparison.

相关文章

软件简介:蓝湖辅助工具,减少移动端开发中控件属性的复制和粘...
现实生活中,我们听到的声音都是时间连续的,我们称为这种信...
前言最近在B站上看到一个漂亮的仙女姐姐跳舞视频,循环看了亿...
【Android App】实战项目之仿抖音的短视频分享App(附源码和...
前言这一篇博客应该是我花时间最多的一次了,从2022年1月底至...
因为我既对接过session、cookie,也对接过JWT,今年因为工作...