Ссылка как ключ в словаре быстрого доступа
Словарь-ключ требует 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
. В моем случае производительность была основным критерием.