В Objective-C мы можем знать, создается ли приложение для устройства или симулятора с использованием макросов:
#if TARGET_IPHONE_SIMULATOR
// Simulator
#else
// Device
#endif
Это макросы времени компиляции и недоступны во время выполнения.
Как добиться того же результата в Swift? Я искал переполнение стека, просмотрел документы и не могу понять.
Несмотря на то, что этот ответ может сработать, рекомендуемое решение для статической проверки (как пояснили несколько инженеров Apple) заключается в определении настраиваемого флага компилятора, предназначенного для симуляторов iOS. Подробные инструкции о том, как это сделать, см. В ответе @mbelsky.
Если вам нужна статическая проверка (например, не во время выполнения, если/иначе), вы не можете обнаружить симулятор напрямую, но вы можете обнаружить 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, как указано в документации:
Конфигурация сборки arch (i386) возвращает true, когда код компилируется для 32-битного симулятора iOS.
Если вы разрабатываете для симулятора, отличного от 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
Кроме того, поскольку флаг заменяется на 0
или 1
препроцессором swift, если вы напрямую используете его в выражении if/else
компилятор выдаст предупреждение о недоступном коде.
Чтобы обойти это предупреждение, см. Один из других ответов.
arch(i386) && os(iOS)
.
os
чек.
УСТАРЕЛО ДЛЯ SWIFT 4.1. #if targetEnvironment(simulator)
используйте #if targetEnvironment(simulator)
. Источник
Для обнаружения симулятора в Swift вы можете использовать конфигурацию сборки:
Теперь вы можете использовать это утверждение для обнаружения симулятора:
#if IOS_SIMULATOR
print("It an iOS Simulator")
#else
print("It a device")
#endif
Также вы можете расширить класс UIDevice:
extension UIDevice {
var isSimulator: Bool {
#if IOS_SIMULATOR
return true
#else
return false
#endif
}
}
// Example of usage: UIDevice.current.isSimulator
Обновленная информация от 20 февраля 2018 г.
Похоже, у @russbishop есть авторитетный ответ, который делает этот ответ "неправильным", хотя он, казалось, работал долгое время.
Определить, создается ли приложение для устройства или симулятора в Swift
Предыдущий ответ
На основе ответа @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 спасибо
От Xcode 9.3
#if targetEnvironment(simulator)
Swift поддерживает новое условие платформы targetEnvironment с одним действительным имитатором аргументов. Условная компиляция формы "#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
}
}
Свифт 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
Теперь вы можете использовать targetEnvironment(simulator)
в качестве аргумента.
#if targetEnvironment(simulator)
// Simulator
#else
// Device
#endif
Обновлено для Xcode 9.3
Позвольте мне уточнить некоторые вещи здесь:
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
Что работает для меня, так как Swift 1.0 проверяет архитектуру, отличную от руки:
#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
В современных системах:
#if targetEnvironment(simulator)
// sim
#else
// device
#endif
Это легко.
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 (и ранее, но я еще не тестировал, насколько раньше), вы можете установить флаг сборки конкретной платформы "-D TARGET_IPHONE_SIMULATOR" для "Any iOS Simulator".
Посмотрите в настройках сборки проекта в разделе "Swift Compiler - Customer Flags", а затем установите флаг в "Other Swift Flags". Вы можете установить флаг конкретной платформы, щелкнув значок "плюс", когда наводите курсор на конфигурацию сборки.
Есть несколько преимуществ сделать это следующим образом: 1) Вы можете использовать тот же условный тест ( "#if TARGET_IPHONE_SIMULATOR" ) в вашем коде Swift и Objective-C. 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
В настоящее время я предпочитаю использовать класс ProcessInfo, чтобы узнать, является ли устройство симулятором и какое устройство используется:
if let simModelCode = ProcessInfo().environment["SIMULATOR_MODEL_IDENTIFIER"] {
print("yes is a simulator :\(simModelCode)")
}
Но, как вы знаете, simModelCode
не очень удобен для немедленного понимания, какой тип симулятора был запущен, поэтому, если вам нужно, вы можете попытаться увидеть этот другой SO- ответ, чтобы определить текущую модель iPhone/устройства и иметь более человекочитаемая строка.
Я использовал этот ниже код в Swift 3
if TARGET_IPHONE_SIMULATOR == 1 {
//simulator
} else {
//device
}
Я надеюсь, что это расширение пригодится
extension UIDevice {
static var isSimulator: Bool = {
var isSimulator = false
#if targetEnvironment(simulator)
isSimulator = true
#endif
return isSimulator
}()
}
Использование:
if UIDevice.isSimulator {
print("running on simulator")
}
Используйте этот код ниже:
#if targetEnvironment(simulator)
// Simulator
#else
// Device
#endif
Работает для Swift 4
и Xcode 9.4.1
Вы также можете получить UIDevice.current.name
, который возвращает iPhone Simulator
, когда он симулятор. Конечно, кто-то может назвать свое устройство "iPhone Simulator"...