Compile time validation and wrapper class generation for configuration files in iOS projects.

TLDR:

I created an open source tool that can help you manage multiple configurations in your iOS projects. The tool partially automates the process of setting up the configurations and generates a safe Swift wrapper class over configuration files. Check out the Github repo.

SwiftConfiguration wrapper class generation
SwiftConfiguration wrapper class generation

The problem

In my last blog post I described a way to handle configuration variables in iOS projects. For me it’s one of the most straightforward way to setup and use configuration variables in your app. Just to sum up my thoughts and explain the process as a TLDR here are the steps to setup multiple configurations in Xcode:

  • Add a project level configuration for each environment
  • Modify the Info.plist file to contain a field that will resolve to the active configuration name at runtime
  • Use the active configuration from the Info.plist file to read properties from a configuration file at runtime

This setup works and I was using it myself in a couple of projects but as time passed (and bugs were introduced), I started to see the downsides of this approach. Since this solution was relying on reading the configuration file through a string API it introduced a whole class of bags when fetching the variables:

  • App will crash if we make a typo in the configuration filename
  • App will crash if the configuration file has an incorrect format
  • App will crash if we make a typo in the property name
  • App will crash if we cast the property to the wrong type
  • App will crash if we try to fetch a property that is not defined in the file

Since Swift is a language that puts a lot of emphasis on safety and preventing runtime crashes, I started to think how could I use it to improve the situation with configuration files. I figured I could write a script for validating the configuration files and generating a Swift wrapper class that I could use to safely fetch the variables. Which is what I did.

The solution

SwiftConfiguration is a build phase script that is used to:

  • Partially automate the setup of multiple configurations
  • Validatate the configuration files for errors at compile time so we can be sure the app won’t crash at runtime when fetching configuration variables
  • Generate a Swift wrapper class that we can use to safely fetch configuration variables using autocomplete

All of this happens at compile time with no additional overhead at runtime. The wrapper class provides safe access to configuration variables and eliminates a whole class of bugs related to typos in the variable names or missing variables. It also resolves the types of the configuration variables so you can be sure that you won’t cast them into a different type.

Project setup

Before using the script you will have to make some additional project setup. First you need to define the configurations that you will be using.

You can do this by clicking on the Project -> Info tab in Xcode (see the below screenshot).

Project configuration- swift
Project configuration

Then you have to create a configuration.plist file that will contain all the variables for the different configurations. The names of the configurations must match the names you previously defined in the project settings (example below).

Example Configuration.plist file- Swift configuration
Example Configuration.plist file

Next, copy the SwiftConfigurationGenerator.swift file from the Github repo into your project structure. Add a new run script in the Build Phase:

Build phase setup- swift configuration
Build phase setup

This will take the configuration file at ${PROJECT_DIR}/Example/Configuration.plist (input) validate the configuration file and generate a type safe wrapper over that file at ${PROJECT_DIR}/Example/ConfigurationProvider.generated.swift (output).

Don’t forget to add the generated file to your project sources so you can use it in your code!

How does it work

I described my take on configuration files in my previous post. That approach worked but it wasn’t very safe since I was relying on a stringy api for fetching the configuration variables from the files. It was also hard to use since there was no autocomplete. This is what SwiftConfiguration does to mitigate the issues:

  • It modifies the Info.plist file to inject a property ($CONFIGURATION) that will be resolved to the current configuration name at runtime.
  • It parses the configuration file and turns it into a custom data structure.
  • It validates the configuration for missing variables. For example if you have a backend_url defined in your Dev configuration you should also have it defined in other configurations to safely use it. The script makes sure all the variables are well defined. If something is wrong you will get compile time error or warning.
  • After the configuration file passes validation the script generates a Swift wrapper class which you can use to fetch the variables with autocomplete. You don’t have to worry about name typos, variables missing in the file or wrong type casts.

Summary

I hope this script will help iOS developers manage their configuration variables more easily and also adds another safety layer to our apps. May it serve you well!

PS: This is the first iteration of this tool and I see a lot of potential to further improve it. If you have any suggestions or problems don’t hesitate to open an issue on Github.