Reputation: 425
Is it possible to create array of different enum types?
E.g.:
MyEnums.swift:
class MyEnums {
enum FirstEnum: String {
case Type1, Type2, Type3
}
enum SecondEnum: String {
case Type1, Type2, Type3
}
}
IteratorManager.swift:
class IteratorManager {
var enumsArray = [MyEnums]()
func iterate() {
for e in enumsArray {
print(e.rawValue)
}
}
}
I tried many solutions - extensions, protocols, grouping in class (like in the example above) in struct or enum - but nothing works.
Upvotes: 1
Views: 1074
Reputation: 425
@kandelvijaya thank you for a good and comprehensive answer.
I have developed some other attitude so far which bases on enum initialization with attributes:
MyEnums.swift:
enum MyEnums {
enum FirstEnum: String {
case Type1, Type2, Type3
}
enum SecondEnum: String {
case Type1, Type2, Type3
}
case First(FirstEnum)
case Second(SecondEnum)
var rawValue: String {
switch self {
case .First(let e):
return e.rawValue
case .Second(let e):
return e.rawValue
}
}
}
IteratorManager.swift:
class IteratorManager {
var enumsArray = [MyEnums]()
func iterate() {
for e in enumsArray {
print(e.rawValue)
}
}
}
Filling array and iterating:
let iteratorManager = IteratorManager()
iteratorManager.enumsArray = [MyEnums.First(MyEnums.FirstEnum.Type1), MyEnums.Second(MyEnums.SecondEnum.Type2)]
iteratorManager.iterate()
It is also type safe (not like the solution with Any).
Furthermore, we can define a sample protocol:
protocol MyEnumsProtocol {
var processedValue: String { get }
static func typeGeneralDescription() -> String
}
implement it:
enum MyEnums {
enum FirstEnum: String, MyEnumsProtocol {
case Type1, Type2, Type3
var processedValue: String {
return "-=\(self)-="
}
static func typeGeneralDescription() -> String {
return "First enum type"
}
}
enum SecondEnum: String, MyEnumsProtocol {
case Type1, Type2, Type3
var processedValue: String {
return "-=\(self)-="
}
static func typeGeneralDescription() -> String {
return "Second enum type"
}
}
case First(FirstEnum)
case Second(SecondEnum)
var rawValue: String {
switch self {
case .First(let e):
return e.rawValue
case .Second(let e):
return e.rawValue
}
}
var subTypeDesc: String {
switch self {
case .First(let e):
return "\(FirstEnum.typeGeneralDescription()): \(e.processedValue)"
case .Second(let e):
return "\(SecondEnum.typeGeneralDescription()): \(e.processedValue)"
}
}
}
and use it like that:
let subTypeDesc = iteratorManager.enumsArray.first?.subTypeDesc
Upvotes: 1
Reputation: 1585
Yes it is but you should be aware of how you do it.
Enums create a concrete Type. Swift is Type Safe language. An array of FirstEnum is not permitted to contain items that are not of type FirstEnum.
However, there is are 2 ways to achieve this. 1. Protocols to the Resuce 2. Type Lie
I will go with both approaches but i will never recommend using the 2nd option although it seems to be simple and eluding.
I will start with the second one.
enum FirstEnum: String {
case Type1, Type2, Type3
}
enum SecondEnum: String {
case Type1, Type2, Type3
}
Lets create some concrete types of enums.
let firstEnum1 = FirstEnum.Type1
let firstEnum2 = FirstEnum.Type2
let secondEnum1 = SecondEnum.Type3
Lets pack them using 2nd option:
let a:[Any] = [firstEnum1, firstEnum2, secondEnum1] //works
Lets see how we can extract it later on:
for index in a {
if let a = index as? FirstEnum { //This is bad
print(a.rawValue)
}
if let a = index as? SecondEnum { //Aweful
print(a.rawValue)
}
}
See we have to cast it back to what we inserted. We have to use expectation and who knows what we get back might be a String instead of Enum. Because Any can take literally Any.
Let see how we can solve this issue by 1st option:
let b:[RawRepresentable] = [firstEnum1, secondEnum1] //Cant do so because of Associated Type
That piece of code does not work because it RawRepresentable is a incomplete type. So we need to define our own protocol.
protocol CustomStringRepresentableEnum {
var rawValue: String { get }
}
Then of course our Enums support rawValue so we can retroactively model this protocol.
extension FirstEnum: CustomStringRepresentableEnum { }
extension SecondEnum: CustomStringRepresentableEnum { }
Now we can create a array of concrete known type.
let b:[CustomStringRepresentableEnum] = [firstEnum1, firstEnum2, secondEnum1]
And this is good because we are not allowed to enter anything besides the thing that conforms to the protocol. This is properly Typed and constrained and compiler will help you a lot to prevent bad things from happening like wrong casting.
Lets use it to prove we wrote some good code.
for index in b {
print(index.rawValue)
}
So there it is. You can have different enums in one array but somehow they need to be homogeneous. You can cheat the compiler with Any and write ugly code or use Protocols and Generics to write effective and robust code. Choice is yours.
Upvotes: 4