Derrick Ho
2 min readDec 27, 2016

Xcode Custom Environment Variables

Some time ago I wrote about Super Preprocessor Directives in an attempt to conditionally compile code from a dynamic framework. Dynamic frameworks are meant to be black boxes and my intent was for any project to be able to toggle on and off some functionality based on the desires of the parent. However, I now believe that this was the wrong approach; I was in actually looking for Environment Variables.

Environment variables are values that can be added to your program at runtime. Imagine you wrote a dynamic framework and wanted to offer the ability to toggle a verbosity options. You can use Environment Variables to set these options in a very simple way.

  1. Edit scheme
  2. Add the Key (i.e. verbose_level) and Value (i.e. silent)

Then you can access this value using ProcessInfo

ProcessInfo.processInfo.environment["verbose_level"]

ProcessInfo.processInfo.environment will give us a dictionary<String,String> which means we can use it to our advantage.

Our dynamic framework will have access to this dictionary which means we can toggle our verbosity levels if we choose to.

if ProcessInfo.processInfo.environment["verbose_level"] == "verbose"
{
print("debug statements")
}

This is a great hidden gem in xcode because now our target application can deliver information to our dynamic framework without doing any modifications programmattically.

— — — -

Also…

Using hard coded strings isn’t the best practice. We should instead use enums

enum EnvironmentVariables: String {
case verbose_level
var value: String {
let v = ProcessInfo.processInfo.environment[rawValue]
return v ?? “”
}
}
// Use case
if EnvironmentVariables.verbose_level.value == "verbose" {
print("debug info")
}

There are two problems with this actually:

  1. Because environment keys are global we should namespace them to prevent overriding some other value.
  2. Difficulty adding new cases

Fixing number one is easy:

enum EnvironmentVariables: String {
case MYAPP_verbose_level // add namespace
}

We just need to add “MYAPP_” to verbose_level in the Environment Variable in Xcode.

Fixing number two means we can’t using enums. Instead we must use structs.

struct EnvironmentVariables: RawRepresentable {
var rawValue: String
static let dnthome_verbose_level = EnvironmentVariables(rawValue: "dnthome_verbose_level")
var value: String {
let v = ProcessInfo.processInfo.environment[rawValue]
return v ?? “”
}
}
// an extension that exists elsewhere
extension EnvironmentVariables {
static let dnthome_something = EnvironmentVariables(rawValue: "dnthome_something")
}