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

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

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

我如何在Swift中实现同样的目标?


当前回答

运行时,但比这里的大多数其他解决方案更简单:

if TARGET_OS_SIMULATOR != 0 {
    // target is current running in the simulator
}

或者,你可以调用一个Objective-C helper函数来返回一个使用预处理器宏的布尔值(特别是如果你已经在你的项目中混合了)。

编辑:不是最好的解决方案,特别是在Xcode 9.3中。请看HotJard的回答

其他回答

斯威夫特4

现在可以使用targetEnvironment(模拟器)作为参数。

#if targetEnvironment(simulator)
    // Simulator
#else
    // Device
#endif

为Xcode 9.3更新

更新30/01/19

虽然这个答案可能有效,但静态检查的推荐解决方案(正如几个苹果工程师所澄清的那样)是定义一个针对iOS模拟器的自定义编译器标志。有关如何操作的详细说明,请参阅@mbelsky的回答。

原来的答案

如果你需要静态检查(例如,不是运行时If /else),你不能直接检测模拟器,但你可以在桌面架构上检测iOS,如下所示

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

Swift 4.1版本之后

最新的使用,现在直接适用于所有在一个条件下所有类型的模拟器只需要适用一个条件-

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

要了解更多信息,请查看Swift提案SE-0190


旧版本-

显然,这在设备上是false,但对于iOS模拟器,它返回true,如文档中所指定的:

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

如果你正在为iOS以外的模拟器开发,你可以简单地改变操作系统参数:

检测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变量(或iOS 8及以下版本的TARGET_IPHONE_SIMULATOR),这在模拟器上是正确的。

请注意,这与使用预处理器标志有所不同,并且有一些限制。例如,你不能在if/else语法无效的地方使用它(例如,在函数作用域之外)。

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

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

此外,由于该标志被swift预处理器替换为0或1,如果你直接在if/else表达式中使用它,编译器将发出关于不可访问代码的警告。

为了解决这个警告,请参阅其他答案之一。

从Swift 1.0开始,对我来说有用的是检查除了arm之外的架构:

#if arch(i386) || arch(x86_64)

     //simulator
#else 
     //device

#endif

在现代系统中:

#if targetEnvironment(simulator)
    // sim
#else
    // device
#endif

就是这么简单。

Xcode 11, Swift 5

    #if !targetEnvironment(macCatalyst)
    #if targetEnvironment(simulator)
        true
    #else
        false        
    #endif
    #endif