Unlock Enum Potential with examples : Swift

Varun Tomar
6 min readMay 12, 2020

--

Photo by Jesus Kiteque on Unsplash

Enum ?? 🤔 The First thought which comes in our mind is they are perfect for managing state in our app. But this is not everything, in Swift it has huge potential 🏋️‍♀️ with armour like associated values, CaseIterable, Recursive Enumerations, Raw Values, Protocols. Let’s move in step by step.

Syntax

The syntax for enumerations is quite straightforward :

  • Use the enum keyword to declare an enumeration, i.e. enum [name] {body} much like as we declare class
  • In the enum body, we have number of cases with the case keyword.
  • Like other types in Swift, enum name starts with a capital letter. Give enumeration types singular rather than plural names, so that they are read as self-evident like “ThemeColor” instead of “themeColors” :
//Use of enum 
let themeColor: ThemeColor = .red
OR
let themeColor = ThemeColor.red

As in code above shown that enum can also be assigned with only dot as well.

Swift enumeration cases doesn’t have an integer value set by default, unlike Objective-C. In the ThemeColor example above; red, green and blue don’t implicitly equal 0,1 and 2. Instead, the different enumeration cases are values in their own right, with an explicitly defined type of ThemeColor.

Enums can have methods, subscripts, and computed properties. But it cannot have stored properties.

Enum with Switch

Combining enum with Switch statement is very neat in Swift, it is exceptionally readable and concise. Also amount of syntax overhead is minimal when we compared it to how we code this with using if and else.

A switch statement must be exhaustive when considering an enumeration’s cases. If the case for .red is omitted in above example, this code doesn’t compile, because it doesn’t consider the complete list of ThemeColor cases. In case we need to omit any case then there must be added “default” case implementation.

Iterating over enum cases

Sometimes it’s useful to have a collection of all enumeration’s cases. It can be achieved by confirming enum to CaseIterable protocol, just by writing “: CaseIterable” after the enumeration’s name. The protocol defines a property allcases which is a collection type.

for theme in ThemeColor.allCases {
print(theme)
}
/// This prints
/// red, green and blue

Associated Values

We can also add more information to the enum cases called associated value. Let’s say you’re writing a payment engine, there could be 3 different payment mode as cash, credit, wallet. But we also need to associate some more value with enum cases. Please refer below image :

Here we have an enum PaymentMode, but we required to associate credit card type with credit as payment mode, also structure “DigitalWallet” type with wallet case. Below is code to make use of it.

let paymentWallet = PaymentMode.wallet(DigitalWallet("amazonPay", "2rh4e34"))let paymentCredit = PaymentMode.credit("Visa")let paymentCash = PaymentMode.cash

It’s interesting huh 🧐 😃

Recursive Enumeration

We can also associate an enumeration type to an enumeration 🤸‍♀️🤸‍♀️. Just need to write indirect before enumeration case, which tells the compiler to insert the necessary layer of indirection. Just like that we are ready for recursive enumeration 🚀. Follow below code example :

enum MathsExpression {case number(Int)indirect case add(MathsExpression, MathsExpression)indirect case subtract(MathsExpression, MathsExpression)}

Above enum can store three kinds of mathematical expressions: a plain number, the addition of two expressions and the subtraction of two expressions. The code below shows how we are going to use this enumeration for maths expression (2+4).

enum MathsExpression {case number(Int)indirect case add(MathsExpression, MathsExpression)indirect case subtract(MathsExpression, MathsExpression)}func evaluate(_ expression: MathsExpression) -> Int {switch expression {case let .number(value):return valuecase let .add(left, right):return evaluate(left) + evaluate(right)case let .subtract(left, right):return evaluate(left) - evaluate(right)}//Usage 
let result = evaluate(MathsExpression.add(MathsExpression.number(2), MathsExpression.number(4)))

We have function “evaluate(_ expression: MathsExpression) -> Int ” to evaluate expression, evaluate function would get called recursively.

Enum Extension

We can add extension to enum as in classes and structure. Refer below example:

Use of Enum over Boolean

Boolean have two states true or false. On the other hand enum could have any number of states but many times it’s very tempting to use boolean as it seems quick and easy solution 😋. It seems like thats not always👊, let me frame an example to make it understand better. We are creating a Driver app to communicate with Rider app, requirement is like a ride can only be assigned to an active driver. At first, it seems like driver can have two mode active or inactive. To handle these states developer reaction might be as : ohh easy one , Where is my Boolean 🧐? Here i come my master 🧞‍♂️, you can create my instance like below :

let isDriverActive: Bool

😀 That’s it, here onwards our implementation will go according to “isDriverActive”. There would be if else handling but we are good to go. I must say hold on!, have a look at below points, these may change your mind for using boolean here :

  1. Readability issue : Boolean can have readability issue for new developer especially for a negative case with a negation condition.
  2. Scalability issue : Product team comes to you with new requirement. Now we have to manage one more state for driver i.e “blocked”. You : - “This is not fair 😠, i have completed my development, now i can’t take these changes.”. Your manager may be like : “Come out of it, you can’t say like this to your team — Your KRA is to develop requirements”…. You might rethink 🤔, let’s add separate boolean for blocked state 🤠 “let isDriverBlocked: Bool”. Now you have two Boolean flags to manage (isDriverActive && isDriverBlocked). Trust me you are going towards dead end 💀💀. Nevertheless this approach is always error prone, remember multiple booleans bring hidden dependencies. But let’s say you did that by making your code flooded with if else statements. Now as your app goes live and on basis of customer feedback, the product team wants you to add one more state for driver i.e “paused” state. Developer 😭 go crazy this time. It’s not fault of product team or customer feedback. The root cause is in our implementation. Our software should adapt changes easily. If we would have used enums, things would have been much better. Just need to add new case for every driver state and handle things using switch.

Even a two cases enum is worth the effort and is a safer bet than boolean flags. Enums make your code future-proof. Booleans are not bad but think twice before you use as they can be easily misused.

Thanks for reading this🙏🙏. Any feedback in the comments would be appreciated. If you enjoyed reading this post, please share and give some claps.

You can follow me for fresh articles.

--

--

Varun Tomar
Varun Tomar

No responses yet