As developers who write code for Apple platforms in Swift, we use enums all the time in order to represent lists of values that are meaningful to our programs. Enums can contain simple cases, but quite often there are raw values matching to each case. As an example, see the following that represents week days; each day has been assigned with an integer number starting from 1:
enun Weekdays: Int {
case monday = 1
case tuesday
case wednesday
case thursday
case friday
case saturday
case sunday
}
Enums with raw values just like the above are pretty handy in programming. We can easily get the raw value of a case using the rawValue property, as well as to get a case based on a raw value. And that is because an enum with raw values automatically conforms to RawRepresentable protocol once we declare the value type.
Usually, raw values are of basic Swift data types, such as Int, String, Double, etc. However, it's absolutely possible to create enums with raw values of custom types as well. There are a couple of rules to follow in order to manage that, but nothing complicated or confusing. That said, let's find out what it takes to create an enum with a custom raw type.
Preparing a custom type
Let's suppose that we want to represent the status of a task visually, and that there is a different color to show for each status case. An enum is obviously the perfect choice to keep all various cases programmatically. But for the purposes of this demonstration, we'll also create a custom type for representing a status color.
Being specific, this new type will contain a string property that represents a color as a hexadecimal value. In addition, a computed property will return the actual color object, so we can use it later in a view.
Here's the implementation of all that:
struct StatusColor {
var hex: String
var color: NSColor {
var intHex: UInt64 = 0
let scanner = Scanner(string: hex)
scanner.scanHexInt64(&intHex)
let red = CGFloat((intHex & 0xFF0000) >> 16) / 255.0
let green = CGFloat((intHex & 0xFF00) >> 8) / 255.0
let blue = CGFloat((intHex & 0xFF)) / 255.0
return NSColor(red: red, green: green, blue: blue, alpha: 1.0)
}
}
Note
Instead of NSColor, A UIColor, or a SwiftUI Color could be returned as well from the color property above. I just chose to demonstrate today's topic in a macOS project.
I mentioned earlier that there are certain rules to follow when it's necessary to create enums with custom raw types. In fact, there are two of them, and they regard the custom type only.
The first rule is that our custom type should conform to the Equatable protocol:
struct StatusColor: Equatable {
...
}
Note that you might need to implement the ==(lhs:rhs:) protocol's method manually if the data types of the stored properties do not conform to Equatable already. This is not the case here, as hex is a String value, and String conforms to Equatable.
The second rule to respect is that the custom type should also conform to any of the following protocols, so it can be expressed as a string, integer, or float literal respectively:
ExpressibleByStringLiteralExpressibleByIntegerLiteralExpressibleByFloatLiteral
In the specific example of this post the StatusColor type must conform to ExpressibleByStringLiteral protocol:
struct StatusColor: Equatable, ExpressibleByStringLiteral {
...
}
By doing that, it becomes mandatory to implement the following initializer in our type as well:
struct StatusColor: Equatable, ExpressibleByStringLiteral {
...
init(stringLiteral value: StringLiteralType) {
hex = value
}
}
The StatusColor type is now ready to be used as the raw type in enums.
An enum with the StatusColor raw type
The following enum represents the various statuses of a task:
enum StatusIndication {
case inProgress
case completed
case stopped
case failed
}
Right now there is no raw type declared, but we'll change that by setting the StatusColor implemented right above. In addition to that, we'll also specify the desired color for each case. But we won't assign StatusColor instances as values; since our type conforms to ExpressibleByStringLiteral protocol, we'll just assign hex string values as shown next, and the compiler will take care of the rest:
enum StatusIndication: StatusColor {
case inProgress = "0000ff"
case completed = "00ff00"
case stopped = "181818"
case failed = "ff0000"
}
Putting in motion the enum with the custom raw type
In a SwiftUI view now, we're going to give a try to the above enum in order to visually show the various statuses along with the matching color. The first thing we'll do is to define an assistive method marked with the @ViewBuilder attribute. The method will return a SwiftUI view, an HStack in particular, which will be containing a title for the status and a color. Here's its implementation:
@ViewBuilder
func status(withTitle title: String, statusIndication: StatusIndication) -> some View {
HStack {
Text(title)
.fontWeight(.medium)
.frame(width: 100)
Color(statusIndication.rawValue.color)
.frame(width: 150, height: 100)
}
}
See that both the status title, as well as the indication are given as arguments. But more important than that is to notice how we access the actual color through the given StatusIndication case; we first access its raw value, which is a ColorStatus object, and then through that the color computed property:
statusIndication.rawValue.color
In the view's body we will call the status(withTitle:statusIndication:) method as many times as the various statuses, passing each time a different case:
var body: some View {
VStack {
status(withTitle: "In progress", statusIndication: .inProgress)
status(withTitle: "Completed", statusIndication: .completed)
status(withTitle: "Stopped", statusIndication: .stopped)
status(withTitle: "Failed", statusIndication: .failed)
}
.frame(width: 350, height: 500)
}
By running this simple app we get this:

Of course, and as it also happens with enums with built-in raw types, we are able to get the case of an enum by providing the raw value. For instance, take a look at the following; at first we create a new StatusColor object, and then we pass it as the raw value to a new StatusIndication value:
let statusColor = StatusColor(stringLiteral: "00ff00")
let indication = StatusIndication(rawValue: statusColor)
print("The status is:", indication!)
// It prints:
// The status is: completed
Watch out however not to provide a raw value that does not match to an actual case; if that happens, the StatusIndication initialization will return a nil value.
Overview
Enums with custom raw types can become a quite powerful tool that can lead in turn to smarter and less code. When creating your own enums with custom types, make sure to comply to the two simple requirements presented previously, and the rest is easy. The simple scenario demonstrated in this post shows all you need to know in order to start using that technique in your own projects, so just go ahead and give it a try. Thank you for reading!