I was wondering: What is the best way to declare a non-ordered list of scalar values in Swift, that are fully backed by a symbol and are liable to be checked by the compiler?
Let's say I want to declare a list of LetterSpacing
values that I want to access and use in my code via their symbols.
My understanding is that I should declare an swift enum
like this:
enum LetterSpacing: Double {
case Short = 1.0
case Medium = 2.0
case Large = 3.0
}
This works fine and gets compiler checks but the annoying part is that I need to LetterSpacing.XXX.rawValue
each time to access the underlying value. The .rawValue
bothers me a bit to have to specify this everywhere.
I suppose it wouldn't make sense or would be inappropriate to declare a struct
with three static let Short = 1.0
etc..
So, how would you handle such cases? Is it possible to add somekind of protocol/extension swift magic to the existing types to be able to have the Short
enum act as its own value? (i.e. let size = LetterSpacing.Short
would be of type Double
and have a value of 1.0
)
The enum
would be preferred for multiple reasons.
First, the enum
actually ends up with a smaller memory footprint. This is because Swift optimizing enum
values into a single byte (no matter what the raw value is), and we only get the full value out of it when we call rawValue
on the enum
value. Paste the following code into a playground to see:
struct LetterSpacingS {
static let Short: Double = 1.0
}
enum LetterSpacingE: Double {
case Short = 1.0
}
sizeofValue(LetterSpacingS.Short)
sizeofValue(LetterSpacingE.Short)
The double
is 8 bytes, while the enum
is just 1.
Second, the importance of the first point extends beyond just memory footprint. It can apply to the execution efficiency of our program as well. If we want to compare two values from our struct, we're comparing 8 bytes. If we want to compare two of our enum values, we comparing just a single byte. We have 1/8th as many bytes to compare in this specific case. And this is just with a double. Consider that Swift enums can also have a string as a backing type. Comparing two strings can be extraordinarily expensive versus just comparing the single byte they're hidden behind in an enum
.
Third, using the enum, we're not comparing floating point numbers, which you really don't want to do, generally speaking.
Fourth, using the enum gives us some type safety that we can't get with the struct of constants. All the struct of constants does is let us define a handful of predefined constants to use.
struct LetterSpacingS {
static let Short = 1.0
static let Medium = 2.0
static let Long = 3.0
}
But now what would a method look like that expects one of these values?
func setLetterSpacing(spacing: Double) {
// do stuff
}
And now what happens when Joe-Coder comes in and does:
foo.setLetterSpacing(-27.861)
Nothing's stopping him. It takes a double, any double. This might not be so common, but if this is in a library you're distributing, you are leaving yourself open to questions and comments like "When I pass a value of 5.0 in, it doesn't look right at all!"
But compare this to using the enum
.
func setLetterSpacing(spacing: LetterSpacing) {
// do stuff
}
And now, we only get the three predefined choices for what to pass into this argument.
And outside of your internal use for the values held by the enum
, you should have to use rawValue
too much.
The fifth reason isn't a strong reason for using an enum over a struct, but mostly just a point to make to eliminate one of the reasons suggested for using a struct over an enum. Swift enums can be nested in other types, and other types can be nested in Swift enums. You don't have to use a struct to get nested types.
I don't see why creating a Struct with three static constants would be inappropriate. I see a lot of Swift code (also from Apple) that does this.
Structs lets you create nice hierarchies:
struct Style {
struct Colors {
static let backgroundColor = UIColor.blackColor()
...
}
struct LetterSpacing {
static let Short = 1.0
}
...
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With