Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/ios/98.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ios 如何在Swift中检测是否正在为设备或模拟器构建应用程序_Ios_Swift - Fatal编程技术网

Ios 如何在Swift中检测是否正在为设备或模拟器构建应用程序

Ios 如何在Swift中检测是否正在为设备或模拟器构建应用程序,ios,swift,Ios,Swift,在Objective-C中,我们可以知道是否正在使用宏为设备或模拟器构建应用程序: #if TARGET_IPHONE_SIMULATOR // Simulator #else // Device #endif 这些是编译时宏,在运行时不可用 如何在Swift中实现同样的效果?19年1月30日更新 虽然这个答案可能有效,但静态检查的推荐解决方案(如几位苹果工程师所阐明的)是定义一个针对iOS模拟器的自定义编译器标志。有关如何执行此操作的详细说明,请参阅 原始答案 如果需要静态检

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

#if TARGET_IPHONE_SIMULATOR
    // Simulator
#else
    // Device
#endif
这些是编译时宏,在运行时不可用

如何在Swift中实现同样的效果?

19年1月30日更新 虽然这个答案可能有效,但静态检查的推荐解决方案(如几位苹果工程师所阐明的)是定义一个针对iOS模拟器的自定义编译器标志。有关如何执行此操作的详细说明,请参阅

原始答案 如果需要静态检查(例如,不是运行时If/else),则无法直接检测模拟器,但可以在桌面架构上检测iOS,如下所示

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

Swift 4.1版之后

最新使用,现在直接适用于所有类型的模拟器,所有模拟器只需应用一个条件-

有关更多说明,您可以查看Swift提案


对于旧版本-

显然,这在设备上是错误的,但对于iOS模拟器,它返回true,如中所述:

为32位iOS模拟器编译代码时,arch(i386)构建配置返回true

如果您是为iOS以外的模拟器开发的,只需更改
os
参数即可:例如:

检测watchOS模拟器

#if (arch(i386) || arch(x86_64)) && os(watchOS)
...
#endif
#if (arch(i386) || arch(x86_64)) && os(tvOS)
...
#endif
#if (arch(i386) || arch(x86_64)) && (os(iOS) || os(watchOS) || os(tvOS))
...
#endif
检测tvOS模拟器

#if (arch(i386) || arch(x86_64)) && os(watchOS)
...
#endif
#if (arch(i386) || arch(x86_64)) && os(tvOS)
...
#endif
#if (arch(i386) || arch(x86_64)) && (os(iOS) || os(watchOS) || os(tvOS))
...
#endif
或者,甚至检测任何模拟器

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

如果您对运行时检查没有问题,则可以检查
TARGET\u OS\u SIMULATOR
变量(或iOS 8及以下版本中的
TARGET\u IPHONE\u SIMULATOR
),该变量在模拟器上是真实的

请注意,这与使用预处理器标志不同,并且稍微受到限制。例如,如果
if/else
在语法上无效(例如,在函数范围之外),您将无法在该位置使用它

例如,假设您希望在设备和模拟器上有不同的导入。这对于动态检查是不可能的,而对于静态检查则是微不足道的

#if (arch(i386) || arch(x86_64)) && os(iOS)
  import Foo
#else
  import Bar
#endif
此外,由于swift预处理器将该标志替换为
0
1
,因此如果您直接在
if/else
表达式中使用该标志,编译器将发出关于无法访问代码的警告


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

由于Swift 1.0正在检查arm以外的体系结构,因此对我有效的方法是:

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

     //simulator
#else 
     //device

#endif

截至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")
}

iOS 9中不推荐使用目标IPHONE模拟器<代码>目标操作系统模拟器是替代品。此外,还提供了
TARGET\u OS\u EMBEDDED

FromTargetConditionals.h


来自Xcode 9.3

#if targetEnvironment(simulator)
Swift支持新的平台条件目标环境,具有 单有效参数模拟器。表格的有条件编译 “if targetEnvironment(simulator)”现在可用于检测构建目标何时为模拟器。Swift编译器将尝试 在以下情况下检测、警告并建议使用targetEnvironment(模拟器) 评估似乎正在测试模拟器的平台条件 通过现有的os()和arch()平台间接创建环境 条件(SE-0190)

iOS 9+:

extension UIDevice {
    static var isSimulator: Bool {
        return NSProcessInfo.processInfo().environment["SIMULATOR_DEVICE_NAME"] != nil
    }
}
extension UIDevice {
    static var isSimulator: Bool {
        return ProcessInfo.processInfo.environment["SIMULATOR_DEVICE_NAME"] != nil
    }
}
extension UIDevice {
    static var isSimulator: Bool {
        return UIDevice.currentDevice().model == "iPhone Simulator"
    }
}
@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 3:

extension UIDevice {
    static var isSimulator: Bool {
        return NSProcessInfo.processInfo().environment["SIMULATOR_DEVICE_NAME"] != nil
    }
}
extension UIDevice {
    static var isSimulator: Bool {
        return ProcessInfo.processInfo.environment["SIMULATOR_DEVICE_NAME"] != nil
    }
}
extension UIDevice {
    static var isSimulator: Bool {
        return UIDevice.currentDevice().model == "iPhone Simulator"
    }
}
@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
在iOS 9之前:

extension UIDevice {
    static var isSimulator: Bool {
        return NSProcessInfo.processInfo().environment["SIMULATOR_DEVICE_NAME"] != nil
    }
}
extension UIDevice {
    static var isSimulator: Bool {
        return ProcessInfo.processInfo.environment["SIMULATOR_DEVICE_NAME"] != nil
    }
}
extension UIDevice {
    static var isSimulator: Bool {
        return UIDevice.currentDevice().model == "iPhone Simulator"
    }
}
@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
目标-C:

extension UIDevice {
    static var isSimulator: Bool {
        return NSProcessInfo.processInfo().environment["SIMULATOR_DEVICE_NAME"] != nil
    }
}
extension UIDevice {
    static var isSimulator: Bool {
        return ProcessInfo.processInfo.environment["SIMULATOR_DEVICE_NAME"] != nil
    }
}
extension UIDevice {
    static var isSimulator: Bool {
        return UIDevice.currentDevice().model == "iPhone Simulator"
    }
}
@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
在Xcode 7.2(以及更早的版本,但我还没有测试更早的版本)中,您可以为“任何iOS模拟器”设置特定于平台的构建标志“-D TARGET\u IPHONE\u SIMULATOR”

查看“Swift编译器-客户标志”下的项目生成设置,然后在“其他Swift标志”中设置标志。当您将鼠标悬停在构建配置上时,可以通过单击“加号”图标来设置特定于平台的标志

这样做有两个好处:1)您可以在Swift和Objective-C代码中使用相同的条件测试(“if TARGET_IPHONE_SIMULATOR”)。2) 您可以编译出只适用于每个构建的变量


对于SWIFT 4.1来说已经过时。如果目标环境(模拟器),则改用
#

要在Swift中检测模拟器,您可以使用构建配置:

  • 在Swift编译器-自定义标志>其他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

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

if TARGET_OS_SIMULATOR != 0 {
    // target is current running in the simulator
}
或者,您可以只调用Objective-C辅助函数,该函数返回一个使用预处理器宏的布尔值(特别是如果您已经在项目中进行了混合)


编辑:不是最好的解决方案,尤其是对于Xcode 9.3。参见

我在Swift 3中使用了以下代码

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

这里所描述的全部达尔文。TargetConditionals

TARGET\u OS\u模拟器-在现代系统中,生成的代码将在模拟器下运行:

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

这很简单。

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

  • TARGET\u OS\u SIMULATOR
    在许多情况下未在Swift代码中设置;由于桥接头,您可能会意外地将其导入,但这是脆弱的,不受支持。这在框架中甚至是不可能的。这就是为什么有些人对Swift是否有效感到困惑
  • 我强烈建议不要将体系结构用作