How can I write a protocol extension to get all rawValues ​​from a Swift enumeration

What I'm trying to do is create a protocol extension to extract an array of raw values ​​from an enumeration. For example, I have the following:

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

How can I implement the EnumIteratable protocol so that I can call TestType.getRawValues ​​() and does it return an array of strings from all raw enum values?

Thanks!

+5
source share
2 answers

You can simply add the static property to return all enumeration values. For instance:

  enum RelationshipStatus: String { case Single = "Single" case Married = "Married" case ItsComplicated = "It complicated" static let all: [RelationshipStatus] = [.Single, .Married, .ItsComplicated] } for status in RelationshipStatus.all { print(status.rawValue) } 
+1
source

Scott's solution is probably the one you want. But if you were looking for something more general that can be applied to arbitrary future enumerations and to resolve additional cases, you can try the following:

First, you need a method for iterating over Enum affairs. I used this implementation here: fooobar.com/questions/19331 / ...

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

Then you can create your protocol that defines the static functions you want:

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

I used a linked type so that allowing enumerations point their type to the protocol. getAllValues not strictly necessary, but it simplifies the logic.

Then you can define your common default implementations:

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

Finally, all you have to do is conform to this protocol every time you need to iterate over an enumeration:

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

The advantage here is that I can add a new case for integrationTest , and I only need to add it in one place.

+3
source

Source: https://habr.com/ru/post/1235436/


All Articles