Application features

Every application contains huge or small amount of features I would like to enable
or disable based on environment – launched from Xcode, outside of Xcode,

Conditional compilation is evil and I’m trying to avoid it. It’s not black & white
and I agree that there are some cases where you can’t avoid it – like Mac App Store –
static code analysis. But that’s not the case now.

Here’s the part of my application delegate.

func applicationDidFinishLaunching(aNotification: NSNotification) {
if Features.MoveToApplications.enabled {
PFMoveToApplicationsFolderIfNecessary()
}
}

Move application to the /Applications folder if application is located
elsewhere and do it only and only if this particular feature is enabled.

Here’s the snippet where I define application features.

enum Features {
static let MoveToApplications = Feature(name: "MOVETOAPPS", defaultState: true)
}

MOVETOAPPS is part of the feature environment variable name. Full name is
FEATURE_MOVETOAPPS_ENABLED. defaultState says if the feature is enabled
or disabled by default and this state is used as well in case where the environment
variable value can’t be parsed.

The beauty comes with Xcode schemes where I can define environment variables
for different actions.

Disable MOVETOAPPS feature when launched from the Xcode.

Another nice thing is that I can (de)activate this environment variable
with checkbox on the left side of my environment variable.

There are other benefits as well:

  • I can disable / enable feature via environment variables in schemes.
  • I’m not forced to touch code and recompile.
  • No accidental commits of disabled features.
  • I’m 100% sure that when I release the application that the feature will
    be there and working.

Nice, isn’t it? Use this or similar way whenever possible to avoid
evil conditional compilation.

And finally here’s the Feature structure I do use.

public struct Feature {
let name: String
let defaultState: Bool

init(name: String, defaultState: Bool) {
self.name = name
self.defaultState = defaultState
}

var enabled: Bool {
guard let stringValue = NSProcessInfo.processInfo().environment["FEATURE_(name)_ENABLED"],
value = Int(stringValue) else {

// Either variable is not set or we can't convert value to integer, ignore it
return defaultState
}

// Like C - 0 is false everything else is true
return value != 0
}
}