Reputation: 129
Im trying to create an enum class with a type and a function that returns all the types.
Initially I have my enum in my object class and a function that returns these as an array:
class someClass: Mappable {
enum Type: Int {
case A = 0
case B = 1
case C = 2
}
}
}
func getAllTypes() -> [Type] {
return [Type.A, Type.B, Type.C]
}
}
The reason i want to extract this out of my object class is because this type is also used in other classes and i don't want to duplicate any unnecessary code.
I can manage to subclass the enum but not the function that returns all the types in an array.
Any help will be appreciated.
Upvotes: 4
Views: 6337
Reputation: 13698
Now you have CaseIterable
. Apple docs. Another topic.
Types that conform to the CaseIterable protocol are typically enumerations without associated values. When using a CaseIterable type, you can access a collection of all of the type’s cases by using the type’s allCases property.
enum Direction: CaseIterable {
case left
case right
case up
case down
}
Direction.allCases.count
Direction.allCases.forEach { print($0) }
Upvotes: 2
Reputation: 73176
all
using an executed-one-time-only closure and AnyGenerator
@vacawama showed how to initialize the all
array in a generalized manner using an executed-one-time-only closure in combination with the failable init(rawValue:)
initialer of enum
's. A slight variation of the method in the fore mentioned answer is to exchange the explicit while
loop and array appending with an AnyGenerator
:
enum Type: Int {
case A = 0, B, C, D, E, F, G, H
static let all: [Type] = {
var rValue = 0
return AnyGenerator<Type> {
defer { rValue += 1 }
return Type(rawValue: rValue)
}.map{$0}
}()
}
print(Type.all)
// [Type.A, Type.B, Type.C, Type.D, Type.E, Type.F, Type.G, Type.H]
This works under the condition that rawValue
's are simply ++
increasing (0, 1, 2, ...
).
all
by conforming the enum
to SequenceType
As another alternative, since your rawValue
's are integer-wise sequential (++
), you could let your enum
conform to SequenceType
, in which case the array of all cases can be easily generated simply by using .map
enum Type: Int, SequenceType {
case A = 0, B, C, D, E, F, G, H
init() { self = A } // Default (first) case intializer
/* conform Type to SequenceType (here: enables only
simple (self.rawValue)...last traversing) */
func generate() -> AnyGenerator<Type> {
var rValue = self.rawValue
return AnyGenerator {
defer { rValue += 1 }
return Type(rawValue: rValue)
}
}
/* use the fact that Type conforms to SequenceType to neatly
initialize your static all array */
static let all = Type().map { $0 }
}
print(Type.all)
// [Type.A, Type.B, Type.C, Type.D, Type.E, Type.F, Type.G, Type.H]
Applying this conformance only to initialize the static all
array is possibly overkill, but a plausible alternative in case you'd like to be able to able to use other aspects of your enum
conforming to SequenceType
for typeCase in Type() {
// treat each type ...
print(typeCase, terminator: " ")
} // A B C D E F G H
for caseFromEAndForward in Type.E {
print(caseFromEAndForward, terminator: " ")
} // E F G H
flatMap
to initialize cases based on a range of rawValue
'sFinally, as a variation of @appzYourLife neat solution, in case you have very many cases, you can use a flatMap
operation on the range of rawValue
's to initialize the static allValues
array, e.g.
enum Type: Int {
case A = 0, B, C, D, E, F, G, H
static let all = (A.rawValue...H.rawValue)
.flatMap{ Type(rawValue: $0) }
}
print(Type.all)
// [Type.A, Type.B, Type.C, Type.D, Type.E, Type.F, Type.G, Type.H]
There's, however, not really any practical use for this method as the general size methods (@vacawama:s or the SequenceType
above) would always be preferable for enums of many cases. The possibly use case I can see for this is if the rawValue
's of the different cases are sequential but not simply by ++
, e.g. if the rawValue
's are used for some bitmasking
// ...
case A = 0, B = 2, C = 4, D = 8, E = 16, F = 32, G = 64, H = 128
The method above would use a method of brute-forcing through the range of rawValue
's, where a minority will actually correspond to actual cases. Somewhat wasteful, but since it's a one-time static initialization, that shouldn't really be an issue.
Upvotes: 4
Reputation: 154523
If your rawValue
s are sequential Int
s, you can take advantage of the fact that the Type(rawValue:)
initializer will fail and return nil
for illegal values to compute Type.all
automatically without having to explicitly list the values or set the range. If you add more cases to your enum, it will automatically adjust:
enum Type: Int {
case A, B, C, D, E, F, G, H, I, J, K
static let all: [Type] = {
var all: [Type] = []
var value = 0
while let e = Type(rawValue: value) {
all.append(e)
value += 1
}
return all
}()
}
print(Type.all)
[Type.A, Type.B, Type.C, Type.D, Type.E, Type.F, Type.G, Type.H, Type.I, Type.J, Type.K]
Upvotes: 2
Reputation: 59496
Why don't you simply add a static property to your enum Type?
enum Type: Int {
case A = 0, B, C
static let all = [A, B, C]
}
Upvotes: 3
Reputation: 1452
You can define a static array that contains all possible values of enum:
static let allValues = [A, B, C]
Then you can use it where you want as :
var allEnumValues = Type.allValues
Upvotes: 1
Reputation: 3278
If it is used in other classes as well then don't put it inside a class
class YourClass : Mappable {
}
enum Type: Int {
case A = 0
case B = 1
case C = 2
}
}
}
Upvotes: 0