Mastering Swift's Development Blog

Follow Us On Twitter
  • Jon Hoffman

Swift – Replacing Static Constants with Enums

Updated: Jul 15


With other programming languages, we regularly used static and static final variables/constants to hold global values that we needed to use within our code but wanted to keep separate from the code itself. For example to create a set of static variables and constants in Java we regularly did something like this:


public class MyStringDefinitions {
    public static String string1 =A string variable”;
    public static String string2 = “Another string variable”;
    public static final String string3 =A string constant”;
}

We could then use these strings within the code like this:


String newString = MyStringDefinitions.string1

Or use them as arguments for methods like this:


Public void myMethod(String inString) {}

myMethod(MyStringDefinitions.string2)

This type of code worked well, because it allowed us to separate where we defined our global values from our code for easier code management, more flexible code and code reuse however there was nothing stopping another developer from using any string that they defined. For example, rather than using the MyStringDefinitions.string2 value to call the myMethod() in the previous example, they could have called the method like this: myMethod(“Hellow World”).


Safety is one of the core principles in the design of the Swift language. Having the ability at compile time to ensure what the developer did is correct, enables us to write applications that are more stable and easier to maintain. With this in mind, Swift gives us a better way to manage these static values using raw values with enums. Let’s look at how we would do this by replacing the MyStringDefinitions class in the previous examples with an Enum:


enum MyStringDefinitions: String {
    case string1 =A string variable”
    case string2 = “Another string variable”
    case string3 =A string constant”
}

Now let’s see how we would use this enum by rewriting the myMethod() Java code in Swift and showing how to call it:


func myMethod(_ inString: MyStringDefinitions) {}

myMethod(.string1)

The advantage we get with this code, is it requires us and other developers to use values defined within the MyStringDefinitions enum when calling this function. This will ensure that developers are restricted to only valid values and that our code will be easier to troubleshoot and maintain in the long term. Now let’s see how I used this in the open source Mastering Swift Cocktails app. If you are not familiar with the cocktails app, you can read about it here.


If you look at the CocktailAPI file within the apps code, you will see several enums defined with raw values. For example the CocktailServiceCall enum is defined like this:


enum CocktailServiceCall: String {
    case random = "https://www.thecocktaildb.com/api/json/$key/random.php"
    case byletter = "https://www.thecocktaildb.com/api/json/$key/search.php?f="
    case byingredint = "https://www.thecocktaildb.com/api/json/$key/filter.php?i="
    case byid = "https://www.thecocktaildb.com/api/json/$key/lookup.php?i="
    case tenrandom = "https://www.thecocktaildb.com/api/json/$key/randomselection.php"
    case popular = "https://www.thecocktaildb.com/api/json/$key/popular.php"
}

This raw values of this enum contains the strings for each of the Cocktail DB API calls that we wish to use within the app to retrieve cocktail information. Notice within the CocktailAPI file, that I separated the calls that returned cocktail information from the calls that returned ingredient information into separate enums. This allows us to ensure that only API calls that return cocktail information are used within methods that return cocktails and only API calls that return ingredient information are used within methods that return ingredients. For example, in the CocktailService struct, the function definition for the function to retrieve cocktail information looks like this:


static func load(_ call: CocktailServiceCall, parameter: String) async -> Cocktails? {
...
}

Notice that the call parameter requires a value from the CocktailServiceCall enum. Then in the IngredientService struct, the function definition for the function to retrieve ingredient information looks like this:


static func load(_ call: IngredientServiceCall, parameter: String) async -> Ingredients? {
}

Notice in the call parameter for this function a value from the IngredientServiceCall enum is required.


Using enums in the place of static values, like strings, makes our code safer, easier to maintain and easier to troubleshoot because we know that only values defined in the enum are being used and other developers are not defining their own values within the code.




masteringSwift.jpeg

Mastering Swift 5.3

The sixth edition of this bestselling book, updated to cover through version 5.3 of the Swift programming language

Amazon

Packt

pop.jpeg

Protocol Oriented Programming

Embrace the Protocol-Oriented design paradigm, for better code maintainability and increased performance, with Swift.

Amazon

Packt