Swift: Failable Enums with Optionals

UPDATE: Here is the cleanest solution (IMO) that was suggested so far. Of course, I still wish enums accepted optionals by default.

A few weeks ago, I wrote about a cool way to store and use multiple Segue Identifiers using Swift enums in your iOS project. As I was trying to use this pattern in a project this week in XCode 6.1, it no longer worked!

Swift Enums

This is because in Swift 1.1, a Swift enum can no longer be initialized with an optional value by default 🙁 …

To make it work, I have to switch my enum from a simple one like this:

    enum SegueIdentifier: String {
        case SegueToRedViewIdentifier = "SegueToRedViewIdentifier"
        case SegueToGreenViewIdentifier = "SegueToGreenViewIdentifier"
        case SegueToBlueViewIdentifier = "SegueToBlueViewIdentifier"
    }

To something a lot more complex with a custom failable initializer that takes in an optional value:

enum SegueIdentifier: String {
        case SegueToRedViewIdentifier = "SegueToRedViewIdentifier"
        case SegueToGreenViewIdentifier = "SegueToGreenViewIdentifier"
        case SegueToBlueViewIdentifier = "SegueToBlueViewIdentifier"
        
        init?(optionalRawValue: String?) {
            if let value = optionalRawValue {
                switch value {
                case "SegueToRedViewIdentifier": self = .SegueToRedViewIdentifier
                case "SegueToGreenViewIdentifier": self = .SegueToGreenViewIdentifier
                case "SegueToBlueViewIdentifier": self = .SegueToBlueViewIdentifier
                default: return nil
                }
            }
            return nil
        }
    }

Of course, at this point, I think it’s less painful to just do two nested if statements:

    enum SegueIdentifier: String {
        case SegueToRedViewIdentifier = "SegueToRedViewIdentifier"
        case SegueToGreenViewIdentifier = "SegueToGreenViewIdentifier"
        case SegueToBlueViewIdentifier = "SegueToBlueViewIdentifier"
    }
    
    override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
        
        if let segueIdentifier = segue.identifier {
            if let segueIdentifierValue =  SegueIdentifier(rawValue: segue.identifier) {
                
                switch segueIdentifierValue {
                case .SegueToRedViewIdentifier:
                    println("red")
                case .SegueToGreenViewIdentifier:
                    println("green")
                case .SegueToBlueViewIdentifier:
                    println("blue")
                }
            }
        }
    }

Or something not as clear / readable using the ?? operator:

    enum SegueIdentifier: String {
        case SegueToRedViewIdentifier = "SegueToRedViewIdentifier"
        case SegueToGreenViewIdentifier = "SegueToGreenViewIdentifier"
        case SegueToBlueViewIdentifier = "SegueToBlueViewIdentifier"

    }
    
    override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
        
        if let segueIdentifier =  SegueIdentifier(
            rawValue: segue.identifier ?? "") {
            
            switch segueIdentifier {
            case .SegueToRedViewIdentifier:
                println("red")
            case .SegueToGreenViewIdentifier:
                println("green")
            case .SegueToBlueViewIdentifier:
                println("blue")
            }
        }
    }

Does anyone have a better way of handling initializing enums with optional values? I’ll make sure to file a radar!

Enjoy the article? Join over 14,500+ Swift developers and enthusiasts who get my weekly updates.