While this answer may work, the recommended solution for a static check (as clarified by several Apple engineers) is to define a custom compiler flag targeting iOS Simulators. For detailed instructions on how do to it, see @mbelsky’s answer.
#if (arch(i386) || arch(x86_64)) && os(iOS) ... #endif
The arch(i386) build configuration returns true when code is compiled for the 32–bit iOS simulator.
If you are developing for a simulator other than iOS, you can simply vary the
os parameter: e.g.
Detect the watchOS simulator
#if (arch(i386) || arch(x86_64)) && os(watchOS) ... #endif
Detect the tvOS simulator
#if (arch(i386) || arch(x86_64)) && os(tvOS) ... #endif
Or, even, detect any simulator
#if (arch(i386) || arch(x86_64)) && (os(iOS) || os(watchOS) || os(tvOS)) ... #endif
If you instead are ok with a runtime check, you can inspect the
TARGET_OS_SIMULATOR variable (or
TARGET_IPHONE_SIMULATOR in iOS 8 and below), which is truthy on a simulator.
Please notice that this is different and slightly more limited than using a preprocessor flag. For instance you won’t be able to use it in place where a
if/else is syntactically invalid (e.g. outside of functions scopes).
Say, for example, that you want to have different imports on the device and on the simulator. This is impossible with a dynamic check, whereas it’s trivial with a static check.
#if (arch(i386) || arch(x86_64)) && os(iOS) import Foo #else import Bar #endif
Also, since the flag is replaced with a
0 or a
1 by the swift preprocessor, if you directly use it in a
if/else expression the compiler will raise a warning about unreachable code.
In order to work around this warning, see one of the other answers.