When developing a Swift app, you will occasionally find yourself wanting to include a piece of code only if you’re running in the simulator. Perhaps you want to run some alternative code paths (like not calling Metal APIs, which aren’t available in the simulator), or avoid attempting to register for push notifications. There are a few ways in which to do this, and the techniques are different depending on whether you’re writing Swift or Objective-C.
This difference often catches people out who have come from Objective-C and are used to using all of the familiar C macros. Let’s cover the right approach for each language.
The Objective-C Approach
If you’re writing Objective-C, this is a breeze to handle. The file TargetConditionals.h
defines the TARGET_OS_SIMULATOR
preprocessor macro which you can check like so:
+ (void)checkCurrentDevice {
#if TARGET_OS_SIMULATOR
NSLog(@"Running in the simulator");
#else
NSLog(@"Running on a device");
#endif
}
Sometimes, you will see TARGET_IPHONE_SIMULATOR
used instead, which is incorrect — this value is deprecated now, and is defined as TARGET_OS_SIMULATOR
.
The Swift Approach
In Swift, this is a little more complicated, as you can’t use the TARGET_OS_SIMULATOR
macro. In fact, per Apple’s documentation you can’t use C preprocessor macros at all:
The Swift compiler does not include a preprocessor. Instead, it takes advantage of compile-time attributes, conditional compilation blocks, and language features to accomplish the same functionality. For this reason, preprocessor directives are not imported in Swift.
This is backed up by Greg Parker:
Swift’s #if doesn’t recognize C macros.
#if TARGET_OS_SIMULATOR
will never be true.
The suggested workaround here is to define a custom flag which is set only for simulator builds, the build setting for which can be found under Active Compilation Conditions
in the custom Swift compiler flags section. Add a sub-setting to the Debug
setting which targets Any iOS Simulator SDK
and add your new macro:
With the custom SIMULATOR
flag defined, you can check for it in Swift using #if
:
#if SIMULATOR
print("Running in the simulator")
#endif