2015-11-07 13 views
5

Quello che sto cercando di fare è creare un'estensione di protocollo per recuperare una matrice di valori non elaborati da un enum. Per esempio dire che ho il seguente:Come posso scrivere un'estensione di protocollo per ottenere tutti i valori raw da un enum Swift

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 
    } 

} 

Come posso implementare l'EnumIteratable protocollo in modo che io possa chiamare TestType.getRawValues ​​() e farlo ritornare un array di stringhe di tutti i valori enum prime?

Grazie!

+0

Forse usando MirrorType? –

+0

@MarceloFabri Un mirror non funzionerà per diversi motivi, uno dei quali è che hai effettivamente bisogno di un'istanza dell'enumerazione, che sto cercando di evitare. Inoltre, le enumerazioni non hanno proprietà :) – JonahGabriel

risposta

1

Si potrebbe semplicemente aggiungere una proprietà statica per restituire tutti i valori enum. Ad esempio:

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

È molto più semplice di quello che stavo pensando. Grazie! – JonahGabriel

2

La soluzione di Scott è probabilmente quella che si desidera. Ma se stavi cercando qualcosa di più generico da applicare a future enumerazioni arbitrarie e consenta ulteriori casi, puoi provare questo:

Per prima cosa, hai bisogno di un metodo per iterare su casi Enum. Ho usato questa implementazione da qui: 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 
    } 
} 

Quindi, è possibile creare il protocollo, che definisce le funzioni statiche che si desidera:

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

ho usato un tipo associato per consentire le enumerazioni conformi a specificare il loro tipo al protocollo. getAllValues non è strettamente necessario, ma semplifica la logica.

Quindi, è possibile definire le implementazioni di default generici:

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 }) 
    } 
} 

Infine, tutto quello che dovete fare è conforme a quel protocollo in qualsiasi momento avete bisogno di iterare l'enumerazione:

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

TestType.getRawValues() 

Il vantaggio qui è che posso aggiungere una nuova custodia per integrationTest e devo solo aggiungerla in un unico posto.

+1

Questo è abbastanza bello e vicino a quello che stavo cercando di realizzare in origine :) Grazie per la soluzione alternativa! – JonahGabriel