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

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

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

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


当前回答

达尔文在这里描述了一切。TargetConditionals: https://github.com/apple/swift-corelibs-foundation/blob/master/CoreFoundation/Base.subproj/SwiftRuntime/TargetConditionals.h

TARGET_OS_SIMULATOR—生成的代码将在模拟器下运行

其他回答

更新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表达式中使用它,编译器将发出关于不可访问代码的警告。

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

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

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

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

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

让我在这里澄清一些事情:

TARGET_OS_SIMULATOR在很多情况下在Swift代码中没有设置;由于桥接头,您可能会意外地导入它,但这是脆弱的,不受支持。这在框架中甚至是不可能的。这就是为什么有些人对这在Swift中是否有效感到困惑。 我强烈建议不要使用架构来代替模拟器。

执行动态检查:

检查ProcessInfo.processInfo。environment["SIMULATOR_DEVICE_NAME"] != nil完全没问题。

您还可以通过检查SIMULATOR_MODEL_IDENTIFIER来获得正在模拟的底层模型,它将返回像iPhone10,3这样的字符串。

执行静态检查:

Xcode 9.2及更早版本:定义你自己的Swift编译标志(如其他答案所示)。

Xcode 9.3+使用新的targetenvirenvironment条件:

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

Xcode 11, Swift 5

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

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

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

     //simulator
#else 
     //device

#endif