В Objective-C мы можем знать, создается ли приложение для устройства или симулятора с использованием макросов:
#if TARGET_IPHONE_SIMULATOR
// Simulator
#else
// Device
#endif
Это макросы времени компиляции, которые недоступны во время выполнения.
Как я могу добиться того же в Swift?
Ответы:
Обновление 30/01/19
Несмотря на то, что этот ответ может работать, рекомендуемое решение для статической проверки (как пояснили несколько инженеров Apple) заключается в определении настраиваемого флага компилятора, предназначенного для симуляторов iOS. Подробные инструкции о том, как это сделать, см. В ответе @ mbelsky .
Оригинальный ответ
Если вам нужна статическая проверка (например, не во время выполнения if / else), вы не можете обнаружить симулятор напрямую, но вы можете обнаружить iOS на настольной архитектуре, как показано ниже
После версии Swift 4.1
Для получения дополнительной информации вы можете проверить предложение Swift SE-0190
Ясно, что это ложно на устройстве, но оно возвращает истину для симулятора iOS, как указано в документации :
Если вы разрабатываете для симулятора, кроме iOS, вы можете просто изменить
os
параметр: например,Определить симулятор watchOS
Определить симулятор tvOS
Или даже обнаружить любой симулятор
Если вместо этого вы согласны с проверкой во время выполнения, вы можете проверить
TARGET_OS_SIMULATOR
переменную (илиTARGET_IPHONE_SIMULATOR
в iOS 8 и ниже), что верно на симуляторе.Обратите внимание, что это отличается и немного более ограничено, чем использование флага препроцессора. Например, вы не сможете использовать его там, где
if/else
синтаксически недопустим (например, за пределами области действия функций).Скажем, например, что вы хотите иметь разные импорты на устройстве и на симуляторе. Это невозможно при динамической проверке, тогда как при статической проверке это тривиально.
Кроме того, поскольку флаг заменяется на
0
или или1
препроцессором swift, если вы непосредственно используете его вif/else
выражении, компилятор выдаст предупреждение о недоступном коде.Чтобы обойти это предупреждение, см. Один из других ответов.
источник
arch(i386) && os(iOS)
.#if targetEnvironment(simulator)
:) ( github.com/apple/swift-evolution/blob/master/proposals/… )УСТАРЕЛО ДЛЯ SWIFT 4.1. Используйте
#if targetEnvironment(simulator)
вместо этого. ИсточникДля обнаружения симулятора в Swift вы можете использовать конфигурацию сборки:
Теперь вы можете использовать это утверждение для обнаружения симулятора:
Также вы можете расширить класс UIDevice:
источник
xcconfig
файлах с помощьюOTHER_SWIFT_FLAGS = TARGET_OS_EMBEDDED
иOTHER_SWIFT_FLAGS[sdk=embeddedsimulator*] = TARGET_OS_SIMULATOR
переопределить для симулятора.Обновленная информация от 20 февраля 2018 г.
Похоже, у @russbishop есть авторитетный ответ, который делает этот ответ «неправильным», хотя он, казалось, работал долгое время.
Определить, создается ли приложение для устройства или симулятора в Swift
Предыдущий ответ
Основываясь на ответах @ WZW и @ Pang, я создал простую структуру утилит. Это решение позволяет избежать предупреждения, создаваемого ответом @ WZW.
Пример использования:
источник
public let IS_SIMULATOR = (TARGET_OS_SIMULATOR != 0)
... то же самое, упрощенно. +1 спасибоTARGET_OS_SIMULATOR != 0
это уже в ответе . Это решение, данное Дэниелом. Нет необходимости добавлять его снова в свободную переменную, он уже есть. Если вы считаете, что иметь его в структуре плохо, а лучше иметь свободную переменную, лучше оставьте комментарий или сделайте свой ответ. Спасибо.От Xcode 9.3
iOS 9+:
Свифт 3:
До iOS 9:
Objective-C:
источник
will never be executed
предупреждениеSwift 4
Теперь вы можете использовать
targetEnvironment(simulator)
в качестве аргумента.Обновлено для 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:
источник
targetEnvironment
приземлился в Xcode 9.3. Вам нужна более новая версия Xcode.Что работает для меня, так как Swift 1.0 проверяет архитектуру, отличную от arm:
источник
Время выполнения, но проще, чем большинство других решений здесь:
Кроме того, вы можете просто вызвать вспомогательную функцию 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 :
источник
Я надеюсь, что это расширение пригодится.
Использование:
источник
В Xcode 7.2 (и ранее, но я не проверял, сколько раньше) вы можете установить специфичный для платформы флаг сборки "-D TARGET_IPHONE_SIMULATOR" для "Любого симулятора iOS".
Посмотрите в настройках сборки проекта в «Swift Compiler - Customer Flags», а затем установите флаг в «Другие флаги Swift». Вы можете установить флаг для конкретной платформы, щелкнув значок «плюс» при наведении указателя мыши на конфигурацию сборки.
Есть несколько преимуществ сделать это следующим образом: 1) Вы можете использовать один и тот же условный тест ("#if TARGET_IPHONE_SIMULATOR") в вашем коде Swift и Objective-C. 2) Вы можете компилировать переменные, которые применяются только к каждой сборке.
Скриншот настроек сборки XCode
источник
Все описанные здесь 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- ответ, чтобы определить текущую модель iPhone / устройства и иметь более человечный читаемая строка.источник
Вот пример Xcode 11 Swift, основанный на удивительном ответе HotJard выше , он также добавляет
isDevice
Bool и используетSIMULATOR_UDID
вместо имени. Переменные присваиваются в каждой строке, чтобы вы могли легче просматривать их в отладчике, если захотите.Там также есть словарь, запись
DTPlatformName
которого должна содержатьsimulator
.источник
Используйте этот код ниже:
Работает для
Swift 4
иXcode 9.4.1
источник
Xcode 11, Swift 5
источник
В дополнение к другим ответам.
В Objective-c, просто убедитесь, что вы включили TargetConditionals .
#include <TargetConditionals.h>
перед использованием
TARGET_OS_SIMULATOR
.источник