2015-05-20 8 views
10

Wörterbuch Schlüssel erfordert Hashable Konformität:Referenz als Schlüssel in schnellen Wörterbuch

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

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

Wie Adresse der reinen Swift Klasseninstanz zu erhalten, wie hashValue zu benutzen?

Antwort

15

für SWIFT 3 (Xcode 8 beta 6 oder höher), verwenden 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 
} 

Dann a == b iff a und b auf die gleiche Instanz der Klasse verweisen ( und a.hashValue == b.hashValue ist in diesem Fall erfüllt).

Beispiel:

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

Für Swift 2.3 und früher Sie

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

zu implementieren einen Hash-Wert, und die Identität des Bedieners === zu implementieren das Equatable Protokoll nutzen könnten.

+0

'unsafeAddressOf' ist das, was ich gesucht habe. Vielen Dank! – Kirsteins

+0

Wird es einen Fall geben, in dem 'unsafeAddressOf' eine andere Adresse für dieselbe Variable zurückgibt? Ich scheine zu haben, in dieses Problem und kann es nicht mehr reproduzieren. Die Adresse wäre eine Sache zunächst sagen, und dann würde es ändern, als ob Swift die Variable im Speicher an anderer Stelle bewegte. * – pixelfreak

+0

Nicht für Instanzen einer * Klasse. Aber siehe http://stackoverflow.com/questions/32638879/swift-strings-and-memory-addresses für einen Fall, in dem es für bestimmte * Werttypen * passieren würde, die implizit mit einem NSObject verbunden sind. –

0

Wenn Sie nicht möchten, oder es ist einfach, eine Objective C Helfer nicht implementieren Hashable aus irgendeinem Grund zu verwenden:

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

long Karten Swift Int und lassen sich perfekt als Dictionary Schlüssel Swift verwendet werden auf 32- und 64-Bit-Architekturen. Es war die schnellste Lösung, die ich gefunden, während verschiedene Ansätze Profilierung, einschließlich unsafeAddress. In meinem Fall war die Leistung das Hauptkriterium.

1

Swift 3

Dieses basiert auf dem großen Code-Schnipsel in Martin R's answer mit aufschlussreichen Kommentar von 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