2015-11-07 7 views
5

Was ich versuche zu tun, ist eine Protokollerweiterung zu erstellen, um ein Array von Rohwerten aus einem Enum zu holen. Zum Beispiel sagen, habe ich folgendes:Wie kann ich eine Protokollerweiterung schreiben, um alle rawValues ​​von einem Swift enum zu bekommen

enum TestType: String, EnumIteratable { 
    case unitTest = "Unit Test" 
    case uiTest = "UI Test" 
} 

class EnumIterator: NSObject { 
    class func iterateEnum<T: Hashable>(_: T.Type) -> AnyGenerator<T> { 
     var i = 0 
     return anyGenerator { 
      let next = withUnsafePointer(&i) { UnsafePointer<T>($0).memory } 
      return next.hashValue == i++ ? next : nil 
     } 
    } 

    class func getValues<T: Hashable>(_: T.Type) -> [T] { 
     let iterator = self.iterateEnum(T) 
     var returnArray = [T]() 
     for val in iterator { 
      returnArray.append(val) 
     } 
     return returnArray 
    } 

} 

Wie kann ich das Protokoll EnumIteratable implementieren, so dass ich TestType.getRawValues ​​() aufrufen können und haben es ein String-Array aller rohen ENUM-Werte zurückgeben?

Danke!

+0

Vielleicht mit MirrorType? –

+0

@MarceloFabri Eine Spiegelung funktioniert aus verschiedenen Gründen nicht, eine davon ist, dass Sie tatsächlich eine Instanz der Enumeration benötigen, die ich vermeiden möchte. Enums haben auch keine Eigenschaften :) – JonahGabriel

Antwort

1

Sie könnten einfach eine statische Eigenschaft hinzufügen, um alle Enum-Werte zurückzugeben. Zum Beispiel:

enum RelationshipStatus: String { 

    case Single = "Single" 
    case Married = "Married" 
    case ItsComplicated = "It's complicated" 

    static let all: [RelationshipStatus] = [.Single, .Married, .ItsComplicated] 

} 

for status in RelationshipStatus.all { 
    print(status.rawValue) 
} 
+1

Das ist viel einfacher als das, was ich dachte. Vielen Dank! – JonahGabriel

2

Scott's Lösung ist wahrscheinlich die, die Sie wollen. Wenn Sie jedoch nach etwas allgemeinerem suchen, das Sie auf beliebige zukünftige Enumerationen anwenden können, und weitere Fälle zulässt, können Sie Folgendes versuchen:

Zuerst benötigen Sie eine Methode, um über Enum-Fälle zu iterieren. Ich habe diese Implementierung von hier: https://stackoverflow.com/a/28341290/914887

func iterateEnum<T: Hashable>(_: T.Type) -> AnyGenerator<T> { 
    var i = 0 
    return anyGenerator { 
     let next = withUnsafePointer(&i) { UnsafePointer<T>($0).memory } 
     return next.hashValue == i++ ? next : nil 
    } 
} 

Dann können Sie Ihr Protokoll erstellen, das die statischen Funktionen definieren Sie wollen:

protocol EnumIteratable { 
    typealias ENUM_TYPE:Hashable, RawRepresentable = Self 
    static func getAllValues() -> [ ENUM_TYPE ] 
    static func getRawValues() -> [ ENUM_TYPE.RawValue ] 
} 

Ich benutzen einen zugehörigen Typen konforme Aufzählungen, damit angeben ihr Typ zum Protokoll. getAllValues ist nicht unbedingt notwendig, aber es vereinfacht die Logik.

Dann können Sie Ihre generische Standardimplementierungen definieren:

extension EnumIteratable { 
    static func getAllValues() -> [ ENUM_TYPE ] 
    { 
     var retval = [ ENUM_TYPE ]() 
     for item in iterateEnum(ENUM_TYPE) 
     { 
      retval.append(item) 
     } 
     return retval 
    } 

    static func getRawValues() -> [ ENUM_TYPE.RawValue ] 
    { 
     return getAllValues().map({ (item:ENUM_TYPE) -> ENUM_TYPE.RawValue in item.rawValue }) 
    } 
} 

schließlich alles, was Sie tun müssen, ist zu diesem Protokoll jedes Mal, wenn Sie über den ENUM iterieren müssen entsprechen:

enum TestType: String, EnumIteratable { 
    case unitTest = "Unit Test" 
    case uiTest = "UI Test" 
} 

TestType.getRawValues() 

Der Vorteil hier ist, dass ich einen neuen Fall für integrationTest hinzufügen kann und ich nur das an einem Ort hinzufügen muss.

+1

Das ist ziemlich cool und nah an dem, was ich ursprünglich erreichen wollte :) Danke für die alternative Lösung! – JonahGabriel

Verwandte Themen