How do I get a list of all possible values of a Swift enum?

This wasn't possible in Swift 1.2 - is it possible in 2.0?

Replies

Not so much. Kicked around the following but it's not all that great and here requires an underlying bounded consecutive int value. If my picture isn't showing, here's an imgur link.


I think you will still have to do it by manually creating a list of all possible values of your enum.


Perhaps it might seem strange that an enum is not enumerable ... But apart from that I don't think it is particularly surprising.


Maybe you could have a look at the new OptionSetType:

https://developer.apple.com/library/prerelease/mac/documentation/Swift/Reference/Swift_OptionSetType_Protocol/index.html

This is at the top of my list as well! I have an app that has an enum with all of the countries and their country codes, and it isn't feasable to return a list of those by hand (it would easily get out of sync with the list and is a large amount of boilerplate).


Here is the closest I have been able to come:

protocol EnumerableEnum {
    static func allValues()->[Self]
    init?(index:Int)
}
extension EnumerableEnum {  
    static func allValues()->[Self] {
        var idx = 0
        return Array(anyGenerator{ return Self(index: idx++)})
    }
}


If you have an Enum with integer values like so:

enum TestEnum:Int,EnumerableEnum{
    case A, B, C
  
    init?(index:Int){
        self.init(rawValue:index)
    }
}


Then you can call the allValues() function to get a list of all values. If it doesn't have integer values, then you can implement the init method (but it doesn't buy you that much over just returning the list by hand).


print(TestEnum.allValues()) // [TestEnum.A, TestEnum.B, TestEnum.C]


A couple of notes:

  • I couldn't add init?(rawValue:) to the protocol for some reason. Hence the init?(index:) initializer
  • Accessing static properties from a protocol extension seems to crash the compiler at the moment, hence the static function
  • Does anyone know how to use the 'where' clause to tell if an enum has Int rawValues? I tried several approaches, but couldn't get any to work. It would be nice to remove the boilerplate init...


Best of all would be if this was built in (and didn't require backing with an Int).

  • I couldn't add init?(rawValue:) to the protocol for some reason. Hence the init?(index:) initializer
  • Does anyone know how to use the 'where' clause to tell if an enum has Int rawValues? I tried several approaches, but couldn't get any to work. It would be nice to remove the boilerplate init...

This works:

protocol EnumerableEnum: RawRepresentable {
    static func allValues() -> [Self]
}
extension EnumerableEnum where RawValue == Int {
    static func allValues() -> [Self] {
        var idx = 0
        return Array(anyGenerator { return Self(rawValue: idx++) })
    }
}
enum TestEnum: Int, EnumerableEnum { // <-- Will not compile unless it has Int RawValues.
    case A, B, C
}
print(TestEnum.allValues())



Accessing static properties from a protocol extension seems to crash the compiler at the moment, hence the static function

Yes, it seems like a compiler bug:

protocol EnumerableEnum: RawRepresentable {
    static var allValues: [Self] { get }
}
extension EnumerableEnum where RawValue == Int {
    static var allValues: [Self] {
        get {
            var idx = 0
            return Array(anyGenerator { return Self(rawValue: idx++) })
        }
    }
}
enum TestEnum: Int, EnumerableEnum {
    case A, B, C
}
//print(TestEnum.allValues) // <-- Uncomment to crash compiler, otherwise compiles w.o. complaining, file bug report?

Thanks Jens!


This provided the key for me. I added the following to my above implementation:

extension RawRepresentable where Self:EnumerableEnum, RawValue == Int {
    init?(index:Int){ self.init(rawValue:index) }
}


Now Enums with Int RawValues will just work! Other forms of Enums can get the same behavior, but they have to provide an implementation for init?(index:)... which I agree is less helpful, but it is there if needed for Enums which are not RawRepresentable.