2015-05-20 18 views
10

klucza Dictionary wymaga Hashable zgodności:referencyjny jako klucz w szybkim słowniku

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

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

Jak uzyskać adres czystego Swift instancji klasy do wykorzystania jako hashValue?

Odpowiedz

15

Dla Swift 3 (Xcode 8 beta 6 lub nowszy), użyj 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 
} 

Następnie a == b IFF a i b odnoszą się do tej samej instancji klasy ( i a.hashValue == b.hashValue jest spełniony w tym przypadku).

przykład:

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 i powyżej, można użyć

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

zaimplementować wartość skrótu, a operator tożsamość === do wdrożenia protokołu Equatable.

+0

'unsafeAddressOf' jest to, czego szukaliśmy. Dzięki! – Kirsteins

+0

Czy będzie przypadek, w którym 'unsafeAddressOf' zwróci inny adres dla tej samej zmiennej? Wydaje mi się, że wpadłem na ten problem i nie mogę go odtworzyć. Ten adres na początku mówi jedno, a potem zmieni się, jakby Swift przesunął zmienną w pamięci gdzie indziej. – pixelfreak

+0

Nie dotyczy instancji klasy * *. Ale zobacz http://stackoverflow.com/questions/32638879/swift-strings-and-memory-addresses dla przypadku, w którym miałoby to miejsce dla pewnych * typów wartości *, które są niejawnie połączone z pewnym NSObject. –

0

Jeśli nie chcą lub nie mogą realizować Hashable z jakiegoś powodu jest to łatwe do korzystania z Objective C pomocnika:

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

long map do Swift Int i może być doskonale wykorzystywane jako klucz Swift Dictionary zarówno na architekturach 32-, jak i 64-bitowych. To było najszybsze rozwiązanie, które znalazłem podczas profilowania różnych podejść, w tym unsafeAddress. W moim przypadku głównym kryterium była wydajność.

1

Swift 3

ta opiera się na wielkim fragmencie kodu w Martin R's answer z cennych uwag od 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 
Powiązane problemy