在Objective-C中,我们可以知道是否正在使用宏为设备或模拟器构建应用程序:
#if TARGET_IPHONE_SIMULATOR
// Simulator
#else
// Device
#endif
这些是编译时宏,在运行时不可用。
如何在Swift中实现相同的目标?我搜索了堆栈溢出,看了一下docs并且无法弄明白。
答案 0 :(得分:291)
虽然这个答案可能有效,但建议的静态检查解决方案(由几位Apple工程师澄清)是定义一个针对iOS模拟器的自定义编译器标志。有关如何操作的详细说明,请参阅@mbelsky's answer。
如果您需要静态检查(例如,不是运行时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
旧版 -
显然,在设备上这是假的,但对于iOS模拟器,它会返回true,如documentation中所述:
当为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
变量(或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
表达式中使用它,编译器将发出无法访问的警告代码。
要解决此警告,请参阅其他答案之一。
答案 1 :(得分:159)
OUTIFT for SWIFT 4.1。请改用#if targetEnvironment(simulator)
。 Source
要在Swift中检测模拟器,您可以使用构建配置:
现在您可以使用此语句来检测模拟器:
#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
答案 2 :(得分:155)
截至2018年2月20日更新的信息
看起来@russbishop有一个权威的答案,使得这个答案不正确" - 即使它似乎工作了很长时间。
Detect if app is being built for device or simulator in Swift
上一个答案
根据@ WZW的回答和@Pang的评论,我创建了一个简单的实用程序结构。这个解决方案避免了@ WZW的回答所产生的警告。
import Foundation
struct Platform {
static var isSimulator: Bool {
return TARGET_OS_SIMULATOR != 0
}
}
使用示例:
if Platform.isSimulator {
print("Running on Simulator")
}
答案 3 :(得分:65)
来自Xcode 9.3
#if targetEnvironment(simulator)
Swift支持一个新的平台条件targetEnvironment 单个有效参数模拟器。条件汇编表格 ' #if targetEnvironment(模拟器)'现在可用于检测构建目标何时是模拟器。 Swift编译器将尝试 检测,警告并建议使用targetEnvironment(模拟器)时 评估似乎正在测试模拟器的平台条件 环境,通过现有的os()和arch()平台 条件。 (SE-0190)
iOS 9 +:
extension UIDevice {
static var isSimulator: Bool {
return NSProcessInfo.processInfo().environment["SIMULATOR_DEVICE_NAME"] != nil
}
}
斯威夫特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"
}
}
<强>目标-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
答案 4 :(得分:50)
您现在可以使用targetEnvironment(simulator)
作为参数。
#if targetEnvironment(simulator)
// Simulator
#else
// Device
#endif
针对Xcode 9.3进行了更新
答案 5 :(得分:27)
让我在这里澄清一些事情:
TARGET_OS_SIMULATOR
未在Swift代码中设置;由于桥接头可能会意外地导入它,但这很脆弱而且不受支持。它在框架中也是不可能的。这就是为什么有些人对这是否适用于Swift感到困惑。执行动态检查:
检查ProcessInfo.processInfo.environment["SIMULATOR_DEVICE_NAME"] != nil
完全没问题。
您还可以通过选中SIMULATOR_MODEL_IDENTIFIER
来获取模拟的基础模型,iPhone10,3
会返回#if targetEnvironment(simulator)
// for sim only
#else
// for device
#endif
等字符串。
执行静态检查:
Xcode 9.2&amp;之前:定义自己的Swift编译标志(如其他答案所示)。
Xcode 9.3+使用新的targetEnvironment条件:
Hybris
答案 6 :(得分:15)
因为Swift 1.0正在检查除arm之外的架构,所以对我有用:
#if arch(i386) || arch(x86_64)
//simulator
#else
//device
#endif
答案 7 :(得分:14)
运行时,但比其他大多数解决方案更简单:
if TARGET_OS_SIMULATOR != 0 {
// target is current running in the simulator
}
或者,您可以调用一个Objective-C辅助函数,该函数返回一个使用预处理器宏的布尔值(特别是如果您已经在项目中混合使用)。
编辑:不是最佳解决方案,尤其是Xcode 9.3。见HotJard's answer
答案 8 :(得分:9)
在现代系统中:
#if targetEnvironment(simulator)
// sim
#else
// device
#endif
它很简单。
答案 9 :(得分:5)
TARGET_IPHONE_SIMULATOR
。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 */
答案 10 :(得分:3)
在Xcode 7.2中(早些时候但我还没有测试过多少),你可以设置一个特定于平台的构建标志&#34; -D TARGET_IPHONE_SIMULATOR&#34; for&#34;任何iOS模拟器&#34;。
查看&#34; Swift Compiler - Customer Flags&#34;下的项目构建设置。然后在&#34;其他Swift Flags&#34;中设置标志。您可以点击“加号”设置特定于平台的标记。将鼠标悬停在构建配置上时的图标。
这样做有以下几个优点:1)您可以在Swift和Objective-C代码中使用相同的条件测试(&#34; #if TARGET_IPHONE_SIMULATOR&#34;)。 2)您可以编译出仅适用于每个构建的变量。
答案 11 :(得分:2)
此处描述 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
答案 12 :(得分:1)
我在Swift 3中使用了以下代码
if TARGET_IPHONE_SIMULATOR == 1 {
//simulator
} else {
//device
}
答案 13 :(得分:1)
当前,我更喜欢使用ProcessInfo类来了解设备是否是模拟器以及正在使用哪种设备:
if let simModelCode = ProcessInfo().environment["SIMULATOR_MODEL_IDENTIFIER"] {
print("yes is a simulator :\(simModelCode)")
}
但是,正如您所知,simModelCode
并不是立即了解启动哪种模拟器的舒适代码,因此,如果需要,您可以尝试查看其他answer以确定当前的iPhone /设备型号,并具有更易读的字符串。
答案 14 :(得分:1)
我希望此扩展程序方便
extension UIDevice {
static var isSimulator: Bool = {
var isSimulator = false
#if targetEnvironment(simulator)
isSimulator = true
#endif
return isSimulator
}()
}
用法:
if UIDevice.isSimulator {
print("running on simulator")
}
答案 15 :(得分:1)
这是一个基于HotJard's出色答案above的Xcode 11 Swift示例,它还添加了isDevice
Bool并使用SIMULATOR_UDID
代替了名称。在每一行都完成了变量分配,因此您可以选择轻松地在调试器中检查它们。
import Foundation
// Extensions to UIDevice based on ProcessInfo.processInfo.environment keys
// to determine if the app is running on an actual device or the Simulator.
@objc extension UIDevice {
static var isSimulator: Bool {
let environment = ProcessInfo.processInfo.environment
let isSimulator = environment["SIMULATOR_UDID"] != nil
return isSimulator
}
static var isDevice: Bool {
let environment = ProcessInfo.processInfo.environment
let isDevice = environment["SIMULATOR_UDID"] == nil
return isDevice
}
}
还有DTPlatformName
的字典条目,其中应包含simulator
。
答案 16 :(得分:1)
除了其他答案。
在Objective-c中,只需确保包含 TargetConditionals 。
#include <TargetConditionals.h>
在使用TARGET_OS_SIMULATOR
之前。
答案 17 :(得分:0)
使用以下代码:
#if targetEnvironment(simulator)
// Simulator
#else
// Device
#endif
适用于Swift 4
和Xcode 9.4.1
答案 18 :(得分:0)
Xcode 11,Swift 5
#if !targetEnvironment(macCatalyst)
#if targetEnvironment(simulator)
true
#else
false
#endif
#endif
答案 19 :(得分:0)
迅速5.2.4 Xcode 11.7
#if targetEnvironment(simulator)
#endif