Ich verwende diesen Code in Xcode 9.3 und Xcode 10 Beta 3-Spielplatz
import Foundation
public protocol EnumCollection: Hashable {
static func cases() -> AnySequence<Self>
}
public extension EnumCollection {
public static func cases() -> AnySequence<Self> {
return AnySequence { () -> AnyIterator<Self> in
var raw = 0
return AnyIterator {
let current: Self = withUnsafePointer(to: &raw) { $0.withMemoryRebound(to: self, capacity: 1) { $0.pointee } }
guard current.hashValue == raw else {
return nil
}
raw += 1
return current
}
}
}
}
enum NumberEnum: EnumCollection{
case one, two, three, four
}
Array(NumberEnum.cases()).count
obwohl beide Swift 4.1 verwenden, liefern sie mir unterschiedliche Ergebnisse für die
auf xcode 9.3 die Größe des Arrays ist 4
und auf xcode 10 beta 3 die Größe des Arrays ist 0
Ich verstehe das überhaupt nicht.
Dies ist eine nicht dokumentierte Methode, um eine Sequenz aller Aufzählungswerte zu erhalten. Die Funktion wurde nur in früheren Swift-Versionen verwendet. Es setzt voraus, dass die Hashwerte der Aufzählungswerte aufeinanderfolgende Ganzzahlen sind, beginnend mit Null.
Das funktioniert definitiv nicht mehr mit Swift 4.2 (auch wenn im Swift 4-Kompatibilitätsmodus ausgeführt wird.), Da Hashwerte jetzt immer Randomisiert sind, siehe SE-0206 Hashable Enhancements :
Um Hash-Werte weniger vorhersehbar zu machen, verwendet die Standard-Hash-Funktion standardmäßig einen zufälligen Startwert pro Ausführung.
Sie können das mit überprüfen
print(NumberEnum.one.hashValue)
print(NumberEnum.two.hashValue)
dabei werden not0
und 1
mit Xcode 10 ausgegeben, jedoch einige andere Werte, die ebenfalls mit jedem Programmlauf variieren.
Eine geeignete Swift 4.2/Xcode 10-Lösung finden Sie unter Wie man eine Aufzählung mit dem String-Typ auflistet? :
extension NumberEnum: CaseIterable { }
print(Array(NumberEnum.allCases).count) // 4
Wenn Sie hashValue einer Aufzählung verwenden, um Fallwerte (Position oder ID) zu bestimmen, ist dies ein falscher Ansatz, da nicht garantiert wird, dass sequentielle int-Werte, 0,1,2, zurückgegeben werden. Ab Swift 4.2
Beispiel: Wenn Sie eine Aufzählung wie diese verwenden:
enum AlertResultType {
case ok, cancel
}
hashValue dieser Aufzählung gibt möglicherweise einen großen int-Wert anstelle von 0 (ok) und 1 (cancel) zurück.
Daher müssen Sie möglicherweise den Aufzählungstyp genauer deklarieren und rowValue verwenden. Zum Beispiel
enum AlertResultType : Int {
case ok = 0, cancel = 1
}
Die Lösung hierfür ist unten für Xcode 10 und Swift 4.2 und höher.
Schritt 1: Protokoll EnumIterable erstellen.
protocol EnumIterable: RawRepresentable, CaseIterable {
var indexValue: Int { get }
}
extension EnumIterable where Self.RawValue: Equatable {
var indexValue: Int {
var index = -1
let cases = Self.allCases as? [Self] ?? []
for (caseIndex, caseItem) in cases.enumerated() {
if caseItem.rawValue == self.rawValue {
index = caseIndex
break
}
}
return index
}
}
Schritt 2: Erweitern Sie das EnumIterator-Protokoll auf Ihr Enum.
enum Colors: String, EnumIterable {
case red = "Red"
case yellow = "Yellow"
case blue = "Blue"
case green = "Green"
}
Schritt 3: Verwenden Sie die indexValue-Eigenschaft wie hashValue.
Colors.red.indexValue
Colors.yellow.indexValue
Colors.blue.indexValue
Colors.green.indexValue
Beispieldruckanweisung und Ausgabe
print("Index Value: \(Colors.red.indexValue), Raw Value: \(Colors.red.rawValue), Hash Value: \(Colors.red.hashValue)")
Ausgabe: "Indexwert: 0, Rohwert: Rot, Hashwert: 1593214705812839748"
print("Index Value: \(Colors.yellow.indexValue), Raw Value: \(Colors.yellow.rawValue), Hash Value: \(Colors.yellow.hashValue)")
Ausgabe: "Indexwert: 1, Rohwert: Gelb, Hashwert: -6836447220368660818"
print("Index Value: \(Colors.blue.indexValue), Raw Value: \(Colors.blue.rawValue), Hash Value: \(Colors.blue.hashValue)")
Ausgabe: "Indexwert: 2, Rohwert: Blau, Hashwert: -8548080225654293616"
print("Index Value: \(Colors.green.indexValue), Raw Value: \(Colors.green.rawValue), Hash Value: \(Colors.green.hashValue)")
Ausgabe: "Indexwert: 3, Rohwert: Grün, Hashwert: 6055121617320138804"