一尘不染

如何在Swift中检测是否正在为设备或模拟器构建应用程序

swift

在Objective-C中,我们可以知道是否正在使用宏为设备或模拟器构建应用程序:

#if TARGET_IPHONE_SIMULATOR
    // Simulator
#else
    // Device
#endif

这些是编译时宏,在运行时不可用。

如何在Swift中实现相同目标?


阅读 330

收藏
2020-07-07

共1个答案

一尘不染

更新30/01/19

尽管此答案可能有效,但建议进行静态检查的解决方案(如几位Apple工程师所阐明的那样)是定义一个针对iOS模拟器的自定义编译器标志。

原始答案

如果您需要静态检查(例如不需要运行时if/else),则无法直接检测到模拟器,但是可以在如下所示的桌面体系结构上检测iOS

#if (arch(i386) || arch(x86_64)) && os(iOS)
    ...
#endif

之后 雨燕4.1 版本

最新用途,现在可以在一种情况下直接用于所有类型的模拟器,而只需要应用一种情况-

#if targetEnvironment(simulator)
  // your simulator code
#else
  // your real device code
#endif

有关更多说明,您可以查看 Swift 提案SE-0190


对于旧版本 -

显然,这在设备上为false,但对于iOS
Simulator,返回的结果为true,如文档中所指定:

为32位iOS模拟器编译代码时,arch(i386)构建配置将返回true。

如果您是为iOS以外的模拟器开发的,则只需更改os参数即可:

检测 watchOS 模拟器

#if (arch(i386) || arch(x86_64)) && os(watchOS)
...
#endif

检测 tvOS 模拟器

#if (arch(i386) || arch(x86_64)) && os(tvOS)
...
#endif

甚至可以检测 任何 模拟器

#if (arch(i386) || arch(x86_64)) && (os(iOS) || os(watchOS) || os(tvOS))
...
#endif

相反,如果可以运行时检查,则可以检查TARGET_OS_SIMULATOR变量(或TARGET_IPHONE_SIMULATOR在iOS
8及更低版本中),这在模拟器上是正确的。

请注意,这与使用预处理器标志不同,并且受到的限制更大。例如,您将无法在a if/else语法上无效的地方使用它(例如,在函数作用域之外)。

例如,假设您要在设备和模拟器上具有不同的导入。对于动态检查,这是不可能的,而对于静态检查,这是微不足道的。

#if (arch(i386) || arch(x86_64)) && os(iOS)
  import Foo
#else
  import Bar
#endif

另外,由于该标志被快速预处理器替换为a 0或a 1,因此,如果直接在if/else表达式中使用它,则编译器将发出有关代码无法到达的警告。

为了变通解决此警告,请参阅其他答案之一。

2020-07-07