Как программно определить, запущено ли приложение в симуляторе iPhone?
Проверка симулятора в Swift: правильный способ
Привет! Ты абсолютно прав, что конструкция из Objective-C не работает напрямую в Swift. Но в Swift есть своя, более изящная и безопасная директива компиляции. Вот как это делается:
#if targetEnvironment(simulator)
// Этот код выполняется ТОЛЬКО в симуляторе
print("Запущено в симуляторе iOS")
#else
// Этот код выполняется ТОЛЬКО на реальном устройстве
print("Запущено на реальном iPhone/iPad")
#endif
Подробное объяснение
Директива targetEnvironment(simulator) — это встроенный флаг компиляции Swift, который проверяет, какая среда выполнения указана в схеме сборки. Она работает на этапе компиляции, поэтому код внутри блоков #if и #else даже не компилируется для противоположной платформы. Это гарантирует, что:
- Код для симулятора не попадёт в бинарник для App Store.
- Код для реального устройства не вызовет ошибок компиляции в симуляторе (например, использование фреймворков, недоступных в симуляторе).
- Проверка работает для всех типов симуляторов: iPhone, iPad, Apple Watch, Apple TV и т.д.
Практический пример с камерой
Допустим, ты хочешь использовать AVFoundation для работы с камерой. На реальном устройстве это работает, а в симуляторе — нет. Вот как это обернуть:
import UIKit
import AVFoundation
class CameraViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
#if targetEnvironment(simulator)
// В симуляторе показываем заглушку
showCameraPlaceholder()
#else
// На реальном устройстве инициируем камеру
setupCameraSession()
#endif
}
private func showCameraPlaceholder() {
let label = UILabel()
label.text = "Камера недоступна в симуляторе"
label.textAlignment = .center
view.addSubview(label)
}
private func setupCameraSession() {
// Здесь код для AVCaptureSession
let captureSession = AVCaptureSession()
// ... настройка камеры
}
}
Важные замечания
- Не используй проверки времени выполнения вроде
UIDevice.current.modelили проверки архитектуры. Они могут работать ненадёжно и не защищают от случайного включения кода для симулятора в релизную сборку. - Директива работает на уровне компиляции, поэтому переменные, объявленные внутри блока
#if, не видны снаружи. Если нужно использовать общие переменные, объявляй их до директивы. - Можно комбинировать с другими флагами. Например,
#if targetEnvironment(simulator) && DEBUG— только для симулятора в отладочной сборке.
Что делать, если нужно проверить симулятор в runtime?
Иногда нужно проверить симулятор не на этапе компиляции, а во время выполнения (например, в библиотеке, которая компилируется заранее). Для этого используй такой трюк:
import Foundation
struct Platform {
static let isSimulator: Bool = {
var isSim = false
#if targetEnvironment(simulator)
isSim = true
#endif
return isSim
}()
}
// Использование:
if Platform.isSimulator {
print("Мы в симуляторе (runtime проверка)")
}
Этот подход создаёт вычисляемое свойство, которое инициализируется один раз при запуске приложения. Оно безопасно для использования в любом месте кода.
<<Альтернативный подход: проверка через ProcessInfo
Если ты не хочешь использовать препроцессорные директивы (например, в случае, когда код поставляется как фреймворк и компилируется отдельно), можно воспользоваться проверкой переменных окружения. Симулятор всегда запускается с определёнными флагами:
import Foundation
func isRunningInSimulator() -> Bool {
return ProcessInfo.processInfo.environment["SIMULATOR_DEVICE_NAME"] != nil
}
// Использование
if isRunningInSimulator() {
print("Обнаружен симулятор через переменные окружения")
}
Плюсы и минусы
- Плюс: Работает в runtime, не требует перекомпиляции для разных платформ. Полезно для библиотек или кода, который не контролирует процесс сборки.
- Минус: Менее надёжно, чем compile-time проверка. Apple может изменить названия переменных окружения в будущих версиях Xcode. Кроме того, эта проверка не защищает от случайного включения кода для симулятора в релизную сборку.
Когда использовать
Этот метод стоит применять только как запасной вариант, когда нет доступа к флагам компиляции. В обычной разработке iOS-приложений всегда предпочитай #if targetEnvironment(simulator) — это стандарт индустрии.