检测是否在Swift中为设备或模拟器构build应用程序

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

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

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

我怎样才能在Swift中实现相同? 我search堆栈溢出,看了看文档,不能弄清楚。

更新14/09/17

虽然这个答案可能会起作用,但推荐的静态检查解决scheme(由多名苹果工程师澄清)是定义一个针对iOS模拟器的自定义编译器标志。 有关如何做的详细说明,请参阅@ mbelsky的答案 。

原始答案

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

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

显然这在设备上是错误的,但是对于iOS模拟器来说它是正确的,正如文档中所指定的那样:

在为32位iOS模拟器编译代码时,arch(i386)构buildconfiguration返回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_SIMULATORvariables(或iOS 8及以下版本中的TARGET_IPHONE_SIMULATOR )。

请注意,这与使用预处理器标志有所不同,稍有限制。 例如,你将无法在if/else语法无效的地方使用它(例如,在函数范围之外)。

比方说,你想在设备和模拟器上有不同的input。 dynamic检查是不可能的,而对于静态检查来说这是微不足道的。

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

另外,由于swift预处理器将标志replace为01 ,所以如果直接在if/elseexpression式中使用它,编译器将会提示有关不可达代码的警告。

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

基于@WZW的回答和@庞的评论,我创build了一个简单的实用程序结构。 这个解决scheme避免了@ WZW的回答产生的警告。

 import Foundation struct Platform { static var isSimulator: Bool { return TARGET_OS_SIMULATOR != 0 } } 

用法示例:

 if Platform.isSimulator { print("Running on Simulator") } 

要在Swift中检测模拟器,可以使用构buildconfiguration:

  • Swift编译器中定义这个configuration-D IOS_SIMULATOR – 自定义标志>其他Swift标志
  • 在此下拉列表中select任何iOS模拟器SDK 下拉列表

现在你可以使用这个语句来检测模拟器:

 #if IOS_SIMULATOR print("It's an iOS Simulator") #else print("It's a device") #endif 

你也可以扩展UIDevice类:

 extension UIDevice { var isSimulator: Bool { #if IOS_SIMULATOR return true #else return false #endif } } // Example of usage: UIDevice.current.isSimulator 

这个怎么样?

iOS 9+:

 extension UIDevice { static var isSimulator: Bool { return NSProcessInfo.processInfo().environment["SIMULATOR_DEVICE_NAME"] != nil } } 

Swift 3:

 extension UIDevice { static var isSimulator: Bool { return ProcessInfo.processInfo.environment["SIMULATOR_DEVICE_NAME"] != nil } } 

在iOS 9之前:

 extension UIDevice { static var isSimulator: Bool { return UIDevice.currentDevice().model == "iPhone Simulator" } } 

Objective-C的:

 @interface UIDevice (Additions) - (BOOL)isSimulator; @end @implementation UIDevice (Additions) - (BOOL)isSimulator { if([[NSProcessInfo processInfo] isOperatingSystemAtLeastVersion:(NSOperatingSystemVersion){9, 0, 0}]) { return [NSProcessInfo processInfo].environment[@"SIMULATOR_DEVICE_NAME"] != nil; } else { return [[self model] isEqualToString:@"iPhone Simulator"]; } } @end 

自从Swift 1.0开始检查arm之外的其他架构之后,

 #if arch(i386) || arch(x86_64) //simulator #else //device #endif 

运行时,但比大多数其他解决scheme更简单:

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

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

TARGET_IPHONE_SIMULATOR在iOS 9中已弃用TARGET_OS_SIMULATOR是替代品。 还有TARGET_OS_EMBEDDED可用。

TargetConditionals.h

 #if defined(__GNUC__) && ( defined(__APPLE_CPP__) || defined(__APPLE_CC__) || defined(__MACOS_CLASSIC__) ) . . . #define TARGET_OS_SIMULATOR 0 #define TARGET_OS_EMBEDDED 1 #define TARGET_IPHONE_SIMULATOR TARGET_OS_SIMULATOR /* deprecated */ #define TARGET_OS_NANO TARGET_OS_WATCH /* deprecated */ 

在Xcode 7.2(及更早的版本,但是我还没有testing过多less),你可以为“Any iOS Simulator”设置一个特定平台的构build标志“-D TARGET_IPHONE_SIMULATOR”。

查看“Swift编译器 – 客户标志”下的项目构build设置,然后在“其他Swift标志”中设置标志。 将鼠标hover在构buildconfiguration上时,可以通过单击“加号”图标来设置特定于平台的标志。

这样做有两个好处:1)您可以在Swift和Objective-C代码中使用相同的条件testing(“#if TARGET_IPHONE_SIMULATOR”)。 2)你可以编译出只适用于每个版本的variables。

Xcode构build设置截图

我在Swift 3中使用了下面的代码

 if TARGET_IPHONE_SIMULATOR == 1 { //simulator } else { //device } 

所有在这里描述的Darwin.TargetConditionals : https : //github.com/apple/swift-corelibs-foundation/blob/master/CoreFoundation/Base.subproj/SwiftRuntime/TargetConditionals.h

TARGET_OS_SIMULATOR - Generated code will run under a simulator

你也可以得到UIDevice.current.name ,当它是iPhone Simulator时它将返回iPhone Simulator 。 当然,有人可以命名他们的设备“iPhone模拟器”…