Environment Variables in Xcode
Creating custom variables & looking into some of the predefined ones in Xcode
According to Wikipedia, an Environment Variable is a dynamic-named value that can affect the way running processes will behave on a computer. They are part of the environment in which a process runs.
It also gives an example, that the process can query for the value of an Environment Variable named ‘TEMP’ to discover the location to store temporary files.
When you are trying to run a server this example makes good sense. Another example will be of getting the port on which the server should run.
Apart from this, one of the most important use of Environment Variables is to pass secret configurations to the process at run time instead of hardcoding it while building and committing it to your repository. This includes but not limited to setting API Keys for a dependency, password or other forms of credentials to authenticate to another service.
Environment Variables are a set of key value pairs that are passed on to the process from outside of the program. The running process will be able to read these values in runtime and make changes to the execution conditions based on it. Ideally these are read only pairs, set once when the execution begins and the program won’t have access to change the values in runtime.
Environment Variables in Xcode
Similar to a process that runs an executable on any Operating System, iOS / iPadOS / macOS applications can make use of this feature to pass specific runtime variables to the applications.
One major difference in the concept of Environment Variables in Apple ecosystem is that the Xcode is responsible for setting these variables to the process and can be set only through that. Once you built the app and install it in the device, launching it via the app launch screen, variables won’t be set.
This is really useful that whatever you write under the influence of Environment Variables, won’t effect your user when they install your app via AppStore or TestFlight.
Setting Environment Variables via Xcode
Environment Variables are set in Xcode under the Scheme Configurations. Arguments Tab allows us to add or remove a specific key value pair in UI. You can even enable or disable specific key value pair in a run.
Ability to save list of keys and to enable or disable it only when required save lot of time when you have several variable options in your application and you don’t have to keep those in memory or refer a different piece of documentation file altogether.
Whatever variables set above is for Run Configuration. These variables can be modified while running test cases.
You can either choose to use the same set of variable available for Run by enabling ‘Use the Run action’s arguments and environment variables’ on top. Or you can disable it and specify entirely new set of values for the keys.
In the example above, I use ‘text_analyzer_log’ to print additional logs related to analyzing the text input from the user, to figure out the aggregate word count or character count in a notes application.
Reading Environment Variables
You can read the environment variables via ProcessInfo API.
For example, the ‘text_analyzer_log’ we set earlier can be read like this:
The ‘environment’ property under ProcessInfo is a dictionary with both keys and values as String. Whatever you passed as environment variables in the scheme will be treated as String, and in case it is of different form, you have to try type casting it.
Using Environment Variables for Debugging / Automation
As we have seen earlier, environment variables are set only when you run the app via Xcode. This makes it a really good candidate in redefining the paths or overriding a specific case while testing, whether it be by running unit tests or running the actual app itself.
For example, you can simply override the whole of your presentation logic when running unit tests. Or disable app analytics when executing paths that fires an analytics event in unit tests / while running automation tests.
In case of automation, environment variables can be used to pass authentication token in order to test post-authentication launches or can be used to clean all the storages while launching the application. Clearing storage is really helpful since we don’t have any methods to actually delete and reinstall the application between test cases.
Predefined Environment Variables
There are several predefined environment variables in Xcode available for debugging purposes. This includes:
- NSZombieEnabled: This controls whether the Foundation runtimes will use zombies. This helps in debugging crashes due to zombies. See more here.
- NSDeallocateZombies: This controls whether Foundation should free all zombies.
- MallocGuardEdges: Enables protecting memory before and after the buffer so that we can catch buffer overflows.
You can read more about predefined environment variables from the links in references.
Few of these predefined debugging controls are now available to enable as a check box within Diagnostics tab under Edit Scheme screen.