Ссылка как ключ в словаре быстрого доступа

Словарь-ключ требует Hashable соответствия:

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

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

Как получить адрес чистого экземпляра класса Swift для использования в качестве hashValue?

Ответ 1

Для Swift 3 (Xcode 8 beta 6 или новее) используйте ObjectIdentifier.

class Test : Hashable {
    // Swift 2:
    var hashValue: Int { return unsafeAddressOf(self).hashValue }
    // Swift 3:
    var hashValue: Int { return ObjectIdentifier(self).hashValue }
}

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

Затем a == b iff a и b относятся к тому же экземпляру класса ( и a.hashValue == b.hashValue выполняется в этом случае).

Пример:

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

Для Swift 2.3 и более ранних версий вы можете использовать

/// 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>

для реализации хэш-значения, а оператор тождества === - выполните протокол Equatable.

Ответ 2

Swift 3

Это основано на замечательном фрагменте кода в ответе Мартина R с проницательным комментарием от Кристофера Свази

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

Если вы не хотите или не можете реализовать Hashable, по какой-то причине легко использовать помощник Objective C:

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

long отображается в Swift Int и может отлично использоваться как клавиша Swift Dictionary на обеих 32 и 64-битных архитектурах. Это было самое быстрое решение, которое я нашел при профилировании различных подходов, включая unsafeAddress. В моем случае производительность была основным критерием.