In C/C++/Objective C you can define a macro using compiler preprocessors. Moreover, you can include/exclude some parts of code using compiler preprocessors.
There is no Swift preprocessor. (For one thing, arbitrary code substitution breaks type- and memory-safety.)
Swift does include build-time configuration options, though, so you can conditionally include code for certain platforms or build styles or in response to flags you define with -D
compiler args. Unlike with C, though, a conditionally compiled section of your code must be syntactically complete. There's a section about this in Using Swift With Cocoa and Objective-C.
For example:
#if os(iOS)
let color = UIColor.redColor()
#else
let color = NSColor.redColor()
#endif
XCODE 9 AND ABOVE
#if DEVELOP
//
#elseif PRODCTN
//
#else
//
#endif
This builds on Jon Willis's answer that relies upon assert, which only gets executed in Debug compilations:
func Log(_ str: String) {
assert(DebugLog(str))
}
func DebugLog(_ str: String) -> Bool {
print(str)
return true
}
My use case is for logging print statements. Here is a benchmark for Release version on iPhone X:
let iterations = 100_000_000
let time1 = CFAbsoluteTimeGetCurrent()
for i in 0 ..< iterations {
Log ("⧉ unarchiveArray:\(fileName) memoryTime:\(memoryTime) count:\(array.count)")
}
var time2 = CFAbsoluteTimeGetCurrent()
print ("Log: \(time2-time1)" )
prints:
Log: 0.0
Looks like Swift 4 completely eliminates the function call.
Use Active Compilation Conditions setting in Build settings / Swift compiler - Custom flags.
ALPHA
, BETA
etc.Then check it with compilation conditions like this:
#if ALPHA
//
#elseif BETA
//
#else
//
#endif
Tip: You can also use
#if !ALPHA
etc.
Another, perhaps simpler, solution that still results in a boolean that you can pass into functions without peppering #if
conditionals throughout your codebase is to define DEBUG
as one of your project build target's Active Compilation Conditions
and include the following (I define it as a global constant):
#if DEBUG
let isDebug = true
#else
let isDebug = false
#endif
This concept builds on kennytm's answer
The main advantage when comparing against kennytm's, is that this does not rely on private or undocumented methods.
In Swift 4:
let isDebug: Bool = {
var isDebug = false
// function with a side effect and Bool return value that we can pass into assert()
func set(debug: Bool) -> Bool {
isDebug = debug
return isDebug
}
// assert:
// "Condition is only evaluated in playgrounds and -Onone builds."
// so isDebug is never changed to true in Release builds
assert(set(debug: true))
return isDebug
}()
Compared with preprocessor macros and kennytm's answer,
-D DEBUG
flag to use it✓ Documented, which means the function will follow normal API release/deprecation patterns.
✓ Using in if/else will not generate a "Will never be executed" warning.