在Objective-C中,我们可以知道是否正在使用宏为设备或模拟器构建应用程序:
#if TARGET_IPHONE_SIMULATOR // Simulator #else // Device #endif
这些是编译时宏,在运行时不可用 .
How can I achieve the same in Swift? 我搜索了堆栈溢出,看了一下docs并且无法搞清楚 .
使用以下代码:
#if targetEnvironment(simulator) // Simulator #else // Device #endif
适用于 Swift 4 和 Xcode 9.4.1
Swift 4
Xcode 9.4.1
虽然这个答案可能有效,但静态检查的推荐解决方案(由几位Apple工程师澄清)是定义一个针对iOS模拟器的自定义编译器标志 . 有关如何操作的详细说明,请参阅@mbelsky's answer .
如果您需要静态检查(例如,不是运行时if / else),则无法直接检测模拟器,但您可以在桌面体系结构上检测iOS,如下所示
#if (arch(i386) || arch(x86_64)) && os(iOS) ... #endif
很明显,这在设备上是错误的,但对于iOS模拟器,它返回true,如documentation中所指定的:
在为32位iOS模拟器编译代码时,arch(i386)构建配置返回true .
如果您正在开发iOS以外的模拟器,您可以简单地改变 os 参数:例如
os
检测 watchOS 模拟器
#if (arch(i386) || arch(x86_64)) && os(watchOS) ... #endif
检测 tvOS 模拟器
#if (arch(i386) || arch(x86_64)) && os(tvOS) ... #endif
或者,甚至,检测 any 模拟器
#if (arch(i386) || arch(x86_64)) && (os(iOS) || os(watchOS) || os(tvOS)) ... #endif
如果您对运行时检查没有问题,则可以检查 TARGET_OS_SIMULATOR 变量(或iOS 8及更低版本中的 TARGET_IPHONE_SIMULATOR ),这在模拟器上是真实的 .
TARGET_OS_SIMULATOR
TARGET_IPHONE_SIMULATOR
请注意,这与使用预处理程序标志不同,稍微有限 . 例如,如果 if/else 在语法上无效(例如在函数范围之外),则无法使用它 .
if/else
例如,假设您希望在设备和模拟器上具有不同的导入 . 通过动态检查这是不可能的,而静态检查则是微不足道的 .
#if (arch(i386) || arch(x86_64)) && os(iOS) import Foo #else import Bar #endif
此外,由于swift预处理器将标志替换为 0 或 1 ,如果直接在 if/else 表达式中使用它,编译器将发出有关无法访问代码的警告 .
0
1
要解决此警告,请参阅其他答案之一 .
Updated Info as of February 20, 2018
看起来@russbishop有一个权威的答案,使得这个答案“不正确” - 即使它似乎工作了很长时间 .
Detect if app is being built for device or simulator in Swift
Previous Answer
根据@ WZW的回答和@Pang的评论,我创建了一个简单的实用程序结构 . 这个解决方案避免了@ WZW回答的警告 .
import Foundation struct Platform { static var isSimulator: Bool { return TARGET_OS_SIMULATOR != 0 } }
用法示例:
if Platform.isSimulator { print("Running on Simulator") }
OUTDATED FOR SWIFT 4.1. 请改用 #if targetEnvironment(simulator) . Source
#if targetEnvironment(simulator)
要在Swift中检测模拟器,您可以使用构建配置:
在Swift编译器中定义此配置 -D IOS_SIMULATOR - 自定义标志>其他Swift标志
在此下拉列表中选择任何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
我希望这个扩展很方便
extension UIDevice { static var isSimulator: Bool = { var isSimulator = false #if targetEnvironment(simulator) isSimulator = true #endif return isSimulator }() }
用法:
if UIDevice.isSimulator { print("running on simulator") }
From Xcode 9.3
Swift支持具有单个有效参数模拟器的新平台条件targetEnvironment . 现在可以使用“#if targetEnvironment(simulator)”形式的条件编译来检测构建目标何时是模拟器 . 当通过现有的os()和arch()平台条件评估似乎间接测试模拟器环境的平台条件时,Swift编译器将尝试检测,警告并建议使用targetEnvironment(模拟器) . (SE-0190)
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 } }
Before 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
您现在可以使用 targetEnvironment(simulator) 作为参数 .
targetEnvironment(simulator)
针对Xcode 9.3进行了更新
让我在这里澄清一些事情:
在许多情况下,
TARGET_OS_SIMULATOR 未在Swift代码中设置;由于桥接头可能会意外地导入它,但这很脆弱而且不受支持 . 它甚至在框架中也是不可能的 . 这就是为什么有些人对Swift是否有效感到困惑 .
我强烈建议不要使用架构作为模拟器的替代品 .
To perform dynamic checks:
检查 ProcessInfo.processInfo.environment["SIMULATOR_DEVICE_NAME"] != nil 完全没问题 .
ProcessInfo.processInfo.environment["SIMULATOR_DEVICE_NAME"] != nil
您还可以通过检查 SIMULATOR_MODEL_IDENTIFIER 来获取正在模拟的基础模型,这将返回像 iPhone10,3 这样的字符串 .
SIMULATOR_MODEL_IDENTIFIER
iPhone10,3
To perform static checks:
Xcode 9.2及更早版本:定义自己的Swift编译标志(如其他答案所示) .
Xcode 9.3使用新的targetEnvironment条件:
#if targetEnvironment(simulator) // for sim only #else // for device #endif
什么对我有用,因为Swift 1.0正在检查除arm之外的架构:
#if arch(i386) || arch(x86_64) //simulator #else //device #endif
运行时,但是比这里的大多数其他解决方案更简单:
if TARGET_OS_SIMULATOR != 0 { // target is current running in the simulator }
或者,您可以调用Objective-C辅助函数,该函数返回使用预处理器宏的布尔值(特别是如果您已经在项目中混合) .
编辑:不是最好的解决方案,特别是从Xcode 9.3开始 . 见HotJard's answer
在现代系统中:
#if targetEnvironment(simulator) // sim #else // device #endif
这很简单 .
TARGET_IPHONE_SIMULATOR 在iOS 9中已弃用. TARGET_OS_SIMULATOR 是替代品 . 也 TARGET_OS_EMBEDDED 可用 .
TARGET_OS_EMBEDDED
来自 TargetConditionals.h :
#if defined(__ GNUC )&&(已定义( APPLE_CPP__)||已定义(__ APPLE_CC__)||已定义(__ MACOS_CLASSIC__)). . .#define TARGET_OS_SIMULATOR 0#define TARGET_OS_EMBEDDED 1#define TARGET_IPHONE_SIMULATOR TARGET_OS_SIMULATOR / 已弃用 /#define TARGET_OS_NANO TARGET_OS_WATCH / 已弃用 /
在Xcode 7.2(以及之前但我之前没有测试过多少)中,您可以为“Any iOS Simulator”设置特定于平台的构建标志“-D TARGET_IPHONE_SIMULATOR” .
查看“Swift Compiler - Customer Flags”下的项目构建设置,然后在“Other Swift Flags”中设置标志 . 将鼠标悬停在构建配置上时,可以通过单击“加号”图标来设置特定于平台的标记 .
这样做有几个好处:1)您可以在Swift和Objective-C代码中使用相同的条件测试(“#if TARGET_IPHONE_SIMULATOR”) . 2)您可以编译出仅适用于每个构建的变量 .
Xcode build settings screenshot
这里所有描述 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
我在Swift 3中使用了以下代码
if TARGET_IPHONE_SIMULATOR == 1 { //simulator } else { //device }
目前,我更喜欢使用ProcessInfo类来了解设备是否是模拟器以及正在使用哪种设备:
if let simModelCode = ProcessInfo().environment["SIMULATOR_MODEL_IDENTIFIER"] { print("yes is a simulator :\(simModelCode)") }
但是,如您所知, simModelCode 不是一个舒适的代码,立即了解哪种模拟器是如此推出的,如果您需要,您可以尝试查看其他SO answer以确定当前的iPhone /设备型号并拥有更多人类可读的字串 .
simModelCode
16 回答
使用以下代码:
适用于
Swift 4
和Xcode 9.4.1
更新14/09/17
虽然这个答案可能有效,但静态检查的推荐解决方案(由几位Apple工程师澄清)是定义一个针对iOS模拟器的自定义编译器标志 . 有关如何操作的详细说明,请参阅@mbelsky's answer .
原始答案
如果您需要静态检查(例如,不是运行时if / else),则无法直接检测模拟器,但您可以在桌面体系结构上检测iOS,如下所示
很明显,这在设备上是错误的,但对于iOS模拟器,它返回true,如documentation中所指定的:
如果您正在开发iOS以外的模拟器,您可以简单地改变
os
参数:例如检测 watchOS 模拟器
检测 tvOS 模拟器
或者,甚至,检测 any 模拟器
如果您对运行时检查没有问题,则可以检查
TARGET_OS_SIMULATOR
变量(或iOS 8及更低版本中的TARGET_IPHONE_SIMULATOR
),这在模拟器上是真实的 .请注意,这与使用预处理程序标志不同,稍微有限 . 例如,如果
if/else
在语法上无效(例如在函数范围之外),则无法使用它 .例如,假设您希望在设备和模拟器上具有不同的导入 . 通过动态检查这是不可能的,而静态检查则是微不足道的 .
此外,由于swift预处理器将标志替换为
0
或1
,如果直接在if/else
表达式中使用它,编译器将发出有关无法访问代码的警告 .要解决此警告,请参阅其他答案之一 .
Updated Info as of February 20, 2018
看起来@russbishop有一个权威的答案,使得这个答案“不正确” - 即使它似乎工作了很长时间 .
Detect if app is being built for device or simulator in Swift
Previous Answer
根据@ WZW的回答和@Pang的评论,我创建了一个简单的实用程序结构 . 这个解决方案避免了@ WZW回答的警告 .
用法示例:
OUTDATED FOR SWIFT 4.1. 请改用
#if targetEnvironment(simulator)
. Source要在Swift中检测模拟器,您可以使用构建配置:
在Swift编译器中定义此配置 -D IOS_SIMULATOR - 自定义标志>其他Swift标志
在此下拉列表中选择任何iOS模拟器SDK
现在您可以使用此语句来检测模拟器:
你也可以扩展UIDevice类:
我希望这个扩展很方便
用法:
From Xcode 9.3
iOS 9+:
Swift 3:
Before iOS 9:
Objective-C:
斯威夫特4
您现在可以使用
targetEnvironment(simulator)
作为参数 .针对Xcode 9.3进行了更新
让我在这里澄清一些事情:
在许多情况下,
TARGET_OS_SIMULATOR
未在Swift代码中设置;由于桥接头可能会意外地导入它,但这很脆弱而且不受支持 . 它甚至在框架中也是不可能的 . 这就是为什么有些人对Swift是否有效感到困惑 .我强烈建议不要使用架构作为模拟器的替代品 .
To perform dynamic checks:
检查
ProcessInfo.processInfo.environment["SIMULATOR_DEVICE_NAME"] != nil
完全没问题 .您还可以通过检查
SIMULATOR_MODEL_IDENTIFIER
来获取正在模拟的基础模型,这将返回像iPhone10,3
这样的字符串 .To perform static checks:
Xcode 9.2及更早版本:定义自己的Swift编译标志(如其他答案所示) .
Xcode 9.3使用新的targetEnvironment条件:
什么对我有用,因为Swift 1.0正在检查除arm之外的架构:
运行时,但是比这里的大多数其他解决方案更简单:
或者,您可以调用Objective-C辅助函数,该函数返回使用预处理器宏的布尔值(特别是如果您已经在项目中混合) .
编辑:不是最好的解决方案,特别是从Xcode 9.3开始 . 见HotJard's answer
在现代系统中:
这很简单 .
TARGET_IPHONE_SIMULATOR
在iOS 9中已弃用.TARGET_OS_SIMULATOR
是替代品 . 也TARGET_OS_EMBEDDED
可用 .来自 TargetConditionals.h :
在Xcode 7.2(以及之前但我之前没有测试过多少)中,您可以为“Any iOS Simulator”设置特定于平台的构建标志“-D TARGET_IPHONE_SIMULATOR” .
查看“Swift Compiler - Customer Flags”下的项目构建设置,然后在“Other Swift Flags”中设置标志 . 将鼠标悬停在构建配置上时,可以通过单击“加号”图标来设置特定于平台的标记 .
这样做有几个好处:1)您可以在Swift和Objective-C代码中使用相同的条件测试(“#if TARGET_IPHONE_SIMULATOR”) . 2)您可以编译出仅适用于每个构建的变量 .
Xcode build settings screenshot
这里所有描述 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
我在Swift 3中使用了以下代码
斯威夫特4:
目前,我更喜欢使用ProcessInfo类来了解设备是否是模拟器以及正在使用哪种设备:
但是,如您所知,
simModelCode
不是一个舒适的代码,立即了解哪种模拟器是如此推出的,如果您需要,您可以尝试查看其他SO answer以确定当前的iPhone /设备型号并拥有更多人类可读的字串 .