Reference as key in swift dictionary

情到浓时终转凉″ 提交于 2019-11-27 03:17:27

问题


Dictionary key requires Hashable conformance:

class Test {}
var dictionary = [Test: String]() // Type 'Test' dies not conform to protocol 'Hashable'

class Test: NSObject {}
var dictionary = [Test: String]() // Works

How to get address of pure Swift class instance to use as hashValue?


回答1:


Equality can be implemented as object identity, i.e. a == b iff a and b refer to the same instance of the class, and the hash value can be build from the ObjectIdentifier (which is the same for identical objects, compare e.g. Difference between using ObjectIdentifier() and '===' Operator):

For Swift 4.2 and later:

class Test : Hashable {
    static func ==(lhs: Test, rhs: Test) -> Bool {
        return lhs === rhs
    }

    public func hash(into hasher: inout Hasher) {
        hasher.combine(ObjectIdentifier(self))
    }
}

For Swift 3:

class Test : Hashable {
    var hashValue: Int { return ObjectIdentifier(self).hashValue }
}

func ==(lhs: Test, rhs: Test) -> Bool {
    return lhs === rhs
}

For Swift 2.3 and earlier, you can use

/// Return an UnsafePointer to the storage used for `object`.  There's
/// not much you can do with this other than use it to identify the
/// object
func unsafeAddressOf(object: AnyObject) -> UnsafePointer<Void>

i.e.

class Test : Hashable {
    var hashValue: Int { return unsafeAddressOf(self).hashValue }
}

func ==(lhs: Test, rhs: Test) -> Bool {
    return lhs === rhs
}

Example:

var dictionary = [Test: String]()
let a = Test()
let b = Test()
dictionary[a] = "A"
print(dictionary[a]) // Optional("A")
print(dictionary[b]) // nil

implement the Equatable protocol.




回答2:


Swift 3

This based on the great code snippet in Martin R's answer with insightful comment from Christopher Swasey

class Test: Hashable, Equatable {
    lazy var hashValue: Int = ObjectIdentifier(self).hashValue

    static func ==(lhs: Test, rhs: Test) -> Bool {
        return lhs === rhs
    }
}

var dictionary = [Test: String]()
let a = Test()
let b = Test()
dictionary[a] = "A"
print(dictionary[a]) // Optional("A")
print(dictionary[b]) // nil



回答3:


If you don't want or cannot implement Hashable for some reason it's easy to use an Objective C helper:

(long )getPtr:(SomeType* )ptr { return (long )ptr; }

long maps to Swift Int and can be perfectly used as a Swift Dictionary key on both 32 and 64bit architectures. It was the fastest solution which I found while profiling different approaches, including unsafeAddress. In my case performance was the main criteria.



来源:https://stackoverflow.com/questions/30345700/reference-as-key-in-swift-dictionary

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!