在Objective-C中,我们可以知道是否正在使用宏为设备或模拟器构建应用程序:
#if TARGET_IPHONE_SIMULATOR
// Simulator
#else
// Device
#endif
这些是编译时宏,在运行时不可用。
如何在Swift中实现相同目标?
在Objective-C中,我们可以知道是否正在使用宏为设备或模拟器构建应用程序:
#if TARGET_IPHONE_SIMULATOR
// Simulator
#else
// Device
#endif
这些是编译时宏,在运行时不可用。
如何在Swift中实现相同目标?
Answers:
尽管此答案可能有效,但是建议进行静态检查的解决方案(如几位Apple工程师所阐明的那样)是定义一个针对iOS模拟器的自定义编译器标志。有关如何执行此操作的详细说明,请参见@mbelsky的答案。
如果需要静态检查(例如不需要运行时if / else),则不能直接检测到模拟器,但是可以在如下所示的桌面体系结构上检测iOS
#if (arch(i386) || arch(x86_64)) && os(iOS)
...
#endif
之后雨燕4.1版本
最新用途,现在直接针对一种条件下的所有类型的所有模拟器都只需要应用一种条件-
#if targetEnvironment(simulator)
// your simulator code
#else
// your real device code
#endif
有关更多说明,您可以查看Swift提案SE-0190
对于旧版本 -
显然,这在设备上为false,但对于iOS Simulator,返回的结果为true,如文档中所指定:
为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
变量(或TARGET_IPHONE_SIMULATOR
在iOS 8及更低版本中),在模拟器上是正确的。
请注意,这与使用预处理器标志不同,并且受到的限制更大。例如,您将无法在以下位置使用它:if/else
语法上无效的(例如,在函数作用域之外)。
例如,假设您要在设备和模拟器上具有不同的导入。对于动态检查,这是不可能的,而对于静态检查,这是微不足道的。
#if (arch(i386) || arch(x86_64)) && os(iOS)
import Foo
#else
import Bar
#endif
另外,由于该标志被快速预处理器替换为a 0
或a 1
,因此如果直接在a中使用它if/else
表达式中则编译器将发出有关代码无法到达的警告。
为了变通解决此警告,请参阅其他答案之一。
#if targetEnvironment(simulator)
:)(github.com/apple/swift-evolution/blob/master/proposals/...)
已过时SWIFT 4.1。使用#if targetEnvironment(simulator)
代替。资源
要在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
xcconfig
通过使用OTHER_SWIFT_FLAGS = TARGET_OS_EMBEDDED
和OTHER_SWIFT_FLAGS[sdk=embeddedsimulator*] = TARGET_OS_SIMULATOR
替代模拟器在文件中进行设置。
截至2018年2月20日的更新信息
看起来@russbishop有一个权威性的答案,即使该答案似乎长期起作用,它也会使该答案“不正确”。
上一个答案
基于@WZW的答案和@Pang的评论,我创建了一个简单的实用程序结构。此解决方案避免了@WZW的回答产生警告。
import Foundation
struct Platform {
static var isSimulator: Bool {
return TARGET_OS_SIMULATOR != 0
}
}
用法示例:
if Platform.isSimulator {
print("Running on Simulator")
}
public let IS_SIMULATOR = (TARGET_OS_SIMULATOR != 0)
...相同的事情,简化了。+1感谢
TARGET_OS_SIMULATOR != 0
是已经在答案。这是丹尼尔提供的解决方案。无需将其再次添加到自由变量中,因为它已经存在。如果您认为将其包含在结构中是不好的,而将其包含在一个自由变量中则更好,那么请对此发表评论或提出自己的答案。谢谢。
从Xcode 9.3
#if targetEnvironment(simulator)
Swift通过一个有效的参数模拟器支持新的平台条件targetEnvironment。现在,可以使用格式为“ #if targetEnvironment(simulator)”的条件编译来检测构建目标何时是模拟器。Swift编译器在评估似乎通过现有os()和arch()平台条件间接测试模拟器环境的平台条件时,将尝试检测,警告并建议使用targetEnvironment(simulator)。(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
will never be executed
警告
让我在这里澄清一些事情:
TARGET_OS_SIMULATOR
在许多情况下,未在Swift代码中设置;您可能由于桥接头而无意中将其导入,但这是脆弱的,不受支持。在框架中甚至也不可能。这就是为什么有些人对此无法在Swift中工作感到困惑的原因。要执行动态检查:
检查ProcessInfo.processInfo.environment["SIMULATOR_DEVICE_NAME"] != nil
是完全可以的。
您还可以通过检查SIMULATOR_MODEL_IDENTIFIER
将返回类似的字符串来获取正在模拟的基础模型iPhone10,3
。
要执行静态检查:
Xcode 9.2及更早版本:定义自己的Swift编译标志(如其他答案所示)。
Xcode 9.3+使用新的targetEnvironment条件:
#if targetEnvironment(simulator)
// for sim only
#else
// for device
#endif
targetEnvironment
登陆Xcode 9.3。您需要更新版本的Xcode。
运行时,但比此处的其他大多数解决方案简单:
if TARGET_OS_SIMULATOR != 0 {
// target is current running in the simulator
}
另外,您可以只调用一个Objective-C帮助程序函数,该函数返回一个使用预处理器宏的布尔值(特别是如果您已经在项目中混合使用的话)。
编辑:不是最好的解决方案,尤其是从Xcode 9.3开始。查看HotJard的答案
== 0
而不是时,只会看到警告!= 0
。else
在Swift 4 Xcode版本9.2(9C40b)中,使用上述方法编写的代码(即使后面有一个代码块)也不会产生任何警告
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(及更早版本中,但我还没有测试过多少),可以为“任何iOS模拟器”设置平台特定的构建标志“ -D TARGET_IPHONE_SIMULATOR”。
在“ Swift编译器-客户标志”下查看项目构建设置,然后在“其他Swift标志”中设置标志。将鼠标悬停在构建配置上时,可以通过单击“加号”图标来设置特定于平台的标志。
这样做有两个优点:1)您可以在Swift和Objective-C代码中使用相同的条件测试(“ #if TARGET_IPHONE_SIMULATOR”)。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
我在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 答案,以确定当前的iPhone /设备型号并拥有更人性化的功能。可读的字符串。
这是一个基于HotJard 上面令人敬畏的答案的Xcode 11 Swift示例,它还添加了一个isDevice
Bool而SIMULATOR_UDID
不是name。变量分配在每一行上完成,因此您可以根据需要在调试器中更轻松地检查它们。
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
。