2015-11-07 10 views
5

Co próbuję zrobić, to utworzyć rozszerzenie protokołu, aby pobrać tablicę surowych wartości z wyliczenia. Na przykład, że mam następujące:Jak napisać rozszerzenie protokołu, aby uzyskać wszystkie wartości surowe z wyliczenia 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 
    } 

} 

Jak mogę wdrożyć EnumIteratable protokołu tak, że mogę zadzwonić TestType.getRawValues ​​() i nie zwróci tablicę ciągów wszystkich surowych wartości enum?

Dzięki!

+0

Może używając MirrorType? –

+0

@MarceloFabri Lustro nie działa z kilku powodów, z których jednym jest to, że faktycznie potrzebujesz instancji enum, której próbuję uniknąć. Również wyliczenia nie mają właściwości :) – JonahGabriel

Odpowiedz

1

Można po prostu dodać właściwość statyczną, aby zwrócić wszystkie wartości wyliczeniowe. Na przykład:

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

To jest łatwiejsze niż to, co myślałem. Dzięki! – JonahGabriel

2

Rozwiązanie Scotta jest prawdopodobnie tym, którego chcesz. Ale jeśli szukasz czegoś bardziej ogólnego, które możesz zastosować do arbitralnych przyszłych wyliczeń i pozwala na dodatkowe przypadki, możesz spróbować tego:

Po pierwsze, potrzebujesz metody do iteracji w przypadku Enum. Użyłem tej implementacji stąd: 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 
    } 
} 

Następnie można utworzyć protokół, który definiuje funkcje statyczne chcesz:

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

użyłem przypisany typ umożliwienie zgodnego enums określić ich typ do protokołu. getAllValues nie jest bezwzględnie konieczne, ale upraszcza logikę.

Następnie można zdefiniować rodzajowe implementacje domyślne:

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

Ostatecznie, wszystko co musisz zrobić, jest zgodne z tym protokołem każdej chwili trzeba iteracyjne nad wyliczenia:

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

TestType.getRawValues() 

Zaletą jest to, że mogę dodać nową skrzynkę dla integrationTest i wystarczy dodać ją w jednym miejscu.

+1

To jest całkiem fajne i bliskie temu, co starałem się osiągnąć pierwotnie :) Dzięki za alternatywne rozwiązanie! – JonahGabriel

Powiązane problemy