From Apple language guide :
Raw values can be strings, characters, or any of the integer or floating-point number types. Each raw value must be unique within its enumeration declaration.
After reading these lines from Apple many people remain under impression that custom types cannot be used as Raw values for enums in Swift.
Actually you might not require doing so in all your programming life. But it is technically possible.
If you go deeper and read language reference from Apple, you will come across following lines
In particular, the raw-value type must conform to the Equatable
protocol and one of the following protocols: ExpressibleByIntegerLiteral
for integer literals, ExpressibleByFloatLiteral
for floating-point literals, ExpressibleByStringLiteral
for string literals that contain any number of characters, and ExpressibleByUnicodeScalarLiteral
or ExpressibleByExtendedGraphemeClusterLiteral
for string literals that contain only a single character. Each case must have a unique name and be assigned a unique raw value.
So for your custom type (Class/Struct) to be used as raw value of enums you will need to conform to Equatable and one of the above mentioned protocols.
Lets take an example.
Suppose you have a product Phone. We want to categorise its color. The color of the phone can be a combination of two colors, front color and back color. We can define our custom Struct for this as follows.
public struct PhoneColor {
var backColor ="Black"
var frontColor ="Silver"
}
As mentioned earlier to qualify to be the raw value of enum our StructPhoneColor must implement Equatable protocol methods. Lets do that.
public struct PhoneColor :Equatable {
var backColor ="Black"
var frontColor ="Silver"
// MARK:- Equatable Methods
public static func ==(lhs:PhoneColor, rhs:PhoneColor) -> Bool {
return(lhs.backColor ==rhs.backColor && lhs.frontColor==rhs.frontColor)
}
}
Can we use PhoneColor as raw value for enum? Lets try that
enum PhoneColorType :PhoneColor { // ERROR: raw type 'PhoneColor' is not expressible by any literal
case blackSilver
case blackBlack
case sliverBlack
case sliverSilver
}
Our custom type PhoneColor is not yet ready to be used as raw value. We will need to implement one of the protocols mentioned in Apple language reference guide. (See above section). In our example we will conform to ExpressibleByStringLiteral. Lets do that. Change the definition of PhoneColor to
public struct PhoneColor :Equatable, ExpressibleByStringLiteral {
var backColor ="Black"
var frontColor ="Silver"
//MARK:- Equatable Methods
public static func ==(lhs:PhoneColor, rhs:PhoneColor) -> Bool {
return(lhs.backColor ==rhs.backColor && lhs.frontColor ==rhs.frontColor)
}
//MARK:- ExpressibleByStringLiteral Methods
public init(stringLiteral value:String) {
let components = value.components(separatedBy:",")
if components.count ==2{
self.backColor = components[0]
self.frontColor =components[1]
}
}
public init(unicodeScalarLiteral value:String) {
self.init(stringLiteral:value)}
public init(extendedGraphemeClusterLiteral value:String) {
self.init(stringLiteral:value)
}
}
Now we have conformed to all the required protocols, our PhoneColor is ready to be used as raw value.
You will notice in the code that in init method, we have assumed that there would be two comma separated values for colors, first values would define back color and the second value would define front color.
Lets use PhoneColor as raw value for enum now.
enum PhoneColorType :PhoneColor {
case blackSilver ="Black,Silver"
case blackBlack ="Black,Black"
case sliverBlack ="Silver,Black"
case sliverSilver ="Silver,Silver"
}
We can now use this enum for our purpose.
Try using it like following
let myColor =PhoneColorType.blackSilver
print(myColor.rawValue.backColor) // prints : Black
print(myColor.rawValue.frontColor) // prints : Silver
Apart from custom type you can make any type provided by Apple, compatible to be used as raw value to enum. By now you should know what you need to do to achiever that. You will need to write extension for those inbuilt types and conform to above mentioned protocols.
So it works.
All said and done. Did you ever think, why is it required for a type to conform to these protocols to be fit for being the raw value for enum?
I will leave it for you to think.
HAPPY LEARNING!!