Can Swift enums have multiple raw values? Can Swift enums have multiple raw values? swift swift

Can Swift enums have multiple raw values?


No, an enum cannot have multiple raw values - it has to be a single value, implementing the Equatable protocol, and be literal-convertible as described in the documentation.

I think the best approach in your case is to use the error code as raw value, and a property backed by a prepopulated static dictionary with the error code as key and the text as value.


You have a couple options. But neither of them involve raw values. Raw values are just not the right tool for the task.

Option 1 (so-so): Associated Values

I personally highly recommend against there being more than one associated value per enum case. Associated values should be dead obvious (since they don't have arguments/names), and having more than one heavily muddies the water.

That said, it's something the language lets you do. This allows you to have each case defined differently as well, if that was something you needed. Example:

enum ErrorType {    case teapot(String, Int)    case skillet(UInt, [CGFloat])}

Option 2 (better): Tuples! And computed properties!

Tuples are a great feature of Swift because they give you the power of creating ad-hoc types. That means you can define it in-line. Sweet!

If each of your error types are going to have a code and a description, then you could have a computed info property (hopefully with a better name?). See below:

enum ErrorType {    case teapot    case skillet    var info: (code: Int, description: String) {        switch self {        case .teapot:            return (418, "Hear me shout!")        case .skillet:            return (326, "I'm big and heavy.")        }    }}

Calling this would be much easier because you could use tasty, tasty dot syntax:

let errorCode = myErrorType.info.code


I created a way of simulating this (No different than what Marcos Crispino suggested on his answer). Far from a perfect solution but allows us to avoid those nasty switch cases for every different property we want to get.

The trick is to use a struct as the "properties/data" holder and using it as a RawValue in the enum itself.

It has a bit of duplication but it's serving me well so far. Every time you want to add a new enum case, the compiler will remind you to fill in the extra case in the rawValue getter, which should remind you to update the init? which would remind you to create the new static property on the struct.

Gist

Code to the Gist:

enum VehicleType : RawRepresentable {    struct Vehicle : Equatable {        let name: String        let wheels: Int        static func ==(l: Vehicle, r: Vehicle) -> Bool {            return l.name == r.name && l.wheels == r.wheels        }        static var bike: Vehicle {            return Vehicle(name: "Bicycle", wheels: 2)        }        static var car: Vehicle {            return Vehicle(name: "Automobile", wheels: 4)        }        static var bus: Vehicle {            return Vehicle(name: "Autobus", wheels: 8)        }    }    typealias RawValue = Vehicle    case car    case bus    case bike    var rawValue: RawValue {        switch self {        case .car:            return Vehicle.car        case .bike:            return Vehicle.bike        case .bus:            return Vehicle.bus        }    }    init?(rawValue: RawValue) {        switch rawValue {        case Vehicle.bike:            self = .bike        case Vehicle.car:            self = .car        case Vehicle.bus:            self = .bus        default: return nil        }    }}VehicleType.bike.rawValue.nameVehicleType.bike.rawValue.wheelsVehicleType.car.rawValue.wheelsVehicleType(rawValue: .bike)?.rawValue.name => "Bicycle"VehicleType(rawValue: .bike)?.rawValue.wheels => 2VehicleType(rawValue: .car)?.rawValue.name => "Automobile"VehicleType(rawValue: .car)?.rawValue.wheels => 4VehicleType(rawValue: .bus)?.rawValue.name => "Autobus"VehicleType(rawValue: .bus)?.rawValue.wheels => 8