Как я могу программно определить, работает ли мое приложение в симуляторе iphone?

Как говорится в вопросе, я в основном хотел бы знать, работает ли мой код в симуляторе, но мне также было бы интересно узнать конкретную версию iphone, которая работает или моделируется.

Обновлено: я добавил слово «программно» к названию вопроса. Суть моего вопроса в том, чтобы иметь возможность динамически включать / исключать код в зависимости от того, какая версия / симулятор работает, поэтому я действительно буду искать что-то вроде директивы препроцессора, которая может предоставить мне эту информацию.

Я не уверен, что директива препроцессора является динамической (хотя в любом случае это может быть то, что вы искали). Директива означает, что вы действительно знали, когда создавали его, где он будет работать.

WiseOldDuck 15.04.2016 22:18

Поскольку я знаю, что моя цель - только новый iPhone или симулятор, мне нравятся __x86_64__ (симулятор iPhone) и __arm64__ (устройство iPhone).

rustyMagnet 01.10.2020 13:58
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
279
2
122 182
21
Перейти к ответу Данный вопрос помечен как решенный

Ответы 21

Обновленный код:

Предполагается, что это работает официально.

#if TARGET_IPHONE_SIMULATOR
NSString *hello = @"Hello, iPhone simulator!";
#elif TARGET_OS_IPHONE
NSString *hello = @"Hello, device!";
#else
NSString *hello = @"Hello, unknown target!";
#endif

Оригинальный пост (поскольку устарело)

Этот код сообщит вам, работаете ли вы в симуляторе.

#ifdef __i386__
NSLog(@"Running in the simulator");
#else
NSLog(@"Running on a device");
#endif

Начиная с iOS 8 и Xcode 6.1.1 TARGET_OS_IPHONE истинен на симуляторе.

malhal 11.01.2015 23:28

это больше не волнует в новых версиях XCode

Fabio Napodano 25.01.2016 21:01

Если только вы не находитесь в 2016 году и не запускаете 64-битный симулятор. Или в 2019 году и запустите свой код на iPhone с процессором Intel.

gnasher729 05.04.2016 11:40
Ответ принят как подходящий

Уже спрашивали, но с совсем другим названием.

Какие #defines устанавливает Xcode при компиляции для iPhone

Я повторю свой ответ оттуда:

Это находится в документации SDK в разделе «Условная компиляция исходного кода».

Соответствующее определение - TARGET_OS_SIMULATOR, которое определено в /usr/include/TargetConditionals.h в рамках iOS. В более ранних версиях цепочки инструментов вам нужно было написать:

#include "TargetConditionals.h"

но в текущей (Xcode 6 / iOS8) цепочке инструментов в этом больше нет необходимости.

Так, например, если вы хотите проверить, что вы работаете на устройстве, вам следует сделать

#if TARGET_OS_SIMULATOR
    // Simulator-specific code
#else
    // Device-specific code
#endif

в зависимости от того, что подходит для вашего варианта использования.

Спасибо. Я согласен с вами, это более конкретная версия вашего исходного вопроса. Если бы ваш вопрос появился в моем первоначальном поиске, мне бы даже не пришлось спрашивать.

Jeffrey Meyer 20.01.2009 00:06

Да, я понимаю, что это нелегко найти в поиске - я просто ссылался на него как на дубликат, чтобы люди могли читать комментарии в обоих местах.

Airsource Ltd 22.01.2009 21:11

Будьте осторожны с этими определениями. Когда вы компилируете код с помощью пункта меню «Проект> Установить активный SDK> Симулятор…», как TARGET_IPHONE_SIMULATOR, так и переменные TARGET_OS_IPHONE определяются! Итак, единственный правильный способ разделения логики указан ниже Питом (спасибо, чувак).

Vadim 24.01.2009 05:05

Верно, но когда вы компилируете для устройства, TARGET_IPHONE_SIMULATOR не устанавливается, так почему бы просто не включить это? Включение i386 зависит от определений инструментальной цепочки и будет недействительным при компиляции на платформе, отличной от x86 (в настоящее время это, конечно, невозможно).

Airsource Ltd 26.01.2009 15:31

Обратите внимание на разницу #if и #ifdef. Для меня это было причиной некорректного поведения.

Anton 09.01.2010 12:32

как сказано здесь: stackoverflow.com/questions/3742525/… это неверно для статических библиотек

cyrilchampier 09.08.2012 12:13

Возможно, необходимость включения TargetConditionals отпала с тех пор, как это было написано, но просто хотел отметить, что #if TARGET_IPHONE_SIMULATOR теперь работает без включения TargetConditionals.h.

dmur 05.03.2014 03:34

Не лучше ли использовать обычный if вместо препроцессора #if, чтобы вы могли получить ошибки компилятора в обоих путях управления? Препроцессор #if не компилирует ветвь, на которую вы в настоящее время не нацеливаетесь. Вы не хотели бы иметь ложное чувство выполненного долга, когда весь ваш код работает на симуляторе, но ваша реальная ветвь устройства сломана.

JoJo 30.07.2015 02:55

Вы можете использовать # if-код, который на самом деле не компилируется на той или иной платформе, но да, вы могли бы использовать if. Не знаете, как это помогает с ложным чувством достижения, вам все равно нужно протестировать его на обеих платформах!

Airsource Ltd 30.07.2015 12:10

Почему скобки () вокруг TARGET_OS_SIMULATOR?

Dimitris 29.04.2016 01:06

Мне нужно было включить в файл Obj-C для iOS 9 с использованием Xcode 7. Хм.

Andrew Duncan 01.06.2016 03:00

@Oren см. stackoverflow.com/questions/24869481/…

Airsource Ltd 19.05.2017 14:58

@Dimitris Это хорошая практика. Вы не знаете, как был определен TARGET_OS_SIMULATOR, поэтому! (TARGET_OS_SIMULATOR) может не совпадать с! TARGET_OS_SIMULATOR

Airsource Ltd 19.05.2017 15:00

Сейчас есть лучший способ сделать это. Смотрите мой ответ в этой теме stackoverflow.com/a/49236898/2272561

Stefan Vasiljevic 20.09.2018 18:02

У меня была та же проблема, и TARGET_IPHONE_SIMULATOR, и TARGET_OS_IPHONE всегда определены и имеют значение 1. Решение Пита, конечно, работает, но если вы когда-нибудь будете использовать что-то другое, кроме Intel (маловероятно, но кто знает), вот что-то, что безопасно, пока оборудование iphone не меняется (так что ваш код всегда будет работать для имеющихся в настоящее время iphone):

#if defined __arm__ || defined __thumb__
#undef TARGET_IPHONE_SIMULATOR
#define TARGET_OS_IPHONE
#else
#define TARGET_IPHONE_SIMULATOR 1
#undef TARGET_OS_IPHONE
#endif

Поместите это в удобное место, а затем сделайте вид, что константы TARGET_* определены правильно.

Не директива препроцессора, но это было то, что я искал, когда подошел к этому вопросу;

NSString *model = [[UIDevice currentDevice] model];
if ([model isEqualToString:@"iPhone Simulator"]) {
    //device is simulator
}
[model compare:iPhoneSimulator] == NSOrderedSame должен быть записан как [model isEqualToString:iPhoneSimulator]
user102008 12.01.2011 01:51

Или [model hasSuffix:@"Simulator"], если вас интересует только «симулятор» в целом, а не iPhone или iPad в частности. Этот ответ не сработает для симулятора iPad :)

Nuthatch 12.08.2014 19:37

Проголосовали за, потому что комментарий Поползня делает это лучшим ответом в целом.

Le Mot Juiced 09.04.2015 22:52

В iOS9 проверьте устройство name вместо model

n.Drake 29.10.2015 11:51

Код не будет работать, если пользователь добавит слово Simulator в имя своего устройства.

mbelsky 09.05.2016 11:12

Лучший способ сделать это:

#if TARGET_IPHONE_SIMULATOR

и нет

#ifdef TARGET_IPHONE_SIMULATOR

поскольку он всегда определен: 0 или 1

Предыдущие ответы немного устарели. Я обнаружил, что все, что вам нужно сделать, это запросить макрос TARGET_IPHONE_SIMULATOR (нет необходимости включать какие-либо другие файлы заголовков [при условии, что вы кодируете для iOS]).

Я попытался использовать TARGET_OS_IPHONE, но он вернул то же значение (1) при работе на реальном устройстве и симуляторе, поэтому я рекомендую вместо этого использовать TARGET_IPHONE_SIMULATOR.

TARGET_OS_IPHONE предназначен для кода, который может работать на iOS или MacOS X. Очевидно, вы хотите, чтобы этот код вел себя как «iPhone» на симуляторе.

gnasher729 05.04.2016 11:41

На мой взгляд, ответ (представленный выше и повторенный ниже):

NSString *model = [[UIDevice currentDevice] model];
if ([model isEqualToString:@"iPhone Simulator"]) {
    //device is simulator
}

- лучший ответ, потому что он, очевидно, выполняется во время RUNTIME, а не является КОМПИЛЬНОЙ ДИРЕКТИВОЙ.

Я не согласен. Этот код попадает в ваш продукт, тогда как директива компилятора избавляет устройство от ненужной рутины.

nine stones 24.10.2013 07:16

Директивы компилятора работают, потому что устройство и симуляторы являются совершенно разными целями компиляции, то есть вы не можете использовать один и тот же двоичный файл на обоих. имеет должен быть скомпилирован для другого оборудования, поэтому в этом случае это имеет смысл.

Brad Parks 13.03.2014 02:52

Выполнение в RUNTIME делает его возможным ответом худший.

gnasher729 05.04.2016 11:43

Все эти ответы хороши, но это как-то сбивает с толку новичков, таких как я, поскольку не разъясняет проверку компиляции и проверку времени выполнения. Препроцессор находится до компиляции, но мы должны сделать его более понятным

Эта статья блога ясно показывает Как определить симулятор iPhone?

Время выполнения

Прежде всего, давайте вкратце обсудим. UIDevice уже предоставляет вам информацию об устройстве

[[UIDevice currentDevice] model]

вернет вам «iPhone Simulator» или «iPhone» в зависимости от того, где запущено приложение.

Время компиляции

Однако вы хотите использовать определения времени компиляции. Почему? Потому что вы компилируете свое приложение строго для запуска либо внутри симулятора, либо на устройстве. Apple делает определение под названием TARGET_IPHONE_SIMULATOR. Итак, давайте посмотрим на код:

#if TARGET_IPHONE_SIMULATOR

NSLog(@"Running in Simulator - no app store or giro");

#endif

Как это лучше других ответов?

mmmmmm 17.06.2014 20:42

@Mark Немного проясняет

onmyway133 18.06.2014 20:52

В настоящее время в Xcode 7 симулятор iOS 9 [[UIDevice currentDevice] model] также возвращает iPhone вместо iPhone Simulator. Так что я думаю, что это не лучший подход.

eMdOS 12.01.2016 22:11

Включить все виды «тренажеров»

NSString *model = [[UIDevice currentDevice] model];
if ([model rangeOfString:@"Simulator" options:NSCaseInsensitiveSearch].location !=NSNotFound)
{
    // we are running in a simulator
}

Это не имеет ничего общего с Xcode 7. Если вы запустите iOS Simulator с iOS8 (из Xcode 7), то это сработает. Это не будет работать для iOS9, где [[UIDevice currentDevice] model] возвращает только «iPhone», если приложение было запущено из iOS Simulator.

nsinvocation 23.09.2015 11:46

почему не -[NSString containsString]?

Gobe 01.11.2016 02:23

Мой ответ основан на ответе @Daniel Magnusson и комментариях @Nuthatch и @ n.Drake. и я пишу его, чтобы сэкономить время для быстрых пользователей, работающих на iOS9 и новее.

Вот что сработало для меня:

if UIDevice.currentDevice().name.hasSuffix("Simulator"){
    //Code executing on Simulator
} else{
    //Code executing on Device
}

Код не будет работать, если пользователь добавит слово Simulator в имя своего устройства.

mbelsky 09.05.2016 11:11

К сожалению, с XCode 8 UIDevice.current.name сообщает имя машины, на которой работает симулятор (обычно что-то вроде «Simon's MacBook Pro» сейчас), поэтому тест стал ненадежным. Я все еще ищу чистый способ исправить это.

Michael 26.09.2016 14:04

В случае Swift мы можем реализовать следующие

Мы можем создать структуру, которая позволяет создавать структурированные данные

struct Platform {
    static var isSimulator: Bool {
        #if targetEnvironment(simulator)
            // We're on the simulator
            return true
        #else
            // We're on a device
             return false
        #endif
    }
}

Затем, если мы хотим определить, создается ли приложение для устройства или симулятора в Swift, тогда.

if Platform.isSimulator {
    // Do one thing
} else {
    // Do the other
}

На мой взгляд, самая чистая реализация, учитывающая архитектуры x86_64 и i386. Помог мне преодолеть странную ошибку устройства и симулятора в Core Data. Ты мужчина!

Iron John Bonney 27.05.2016 01:01

В Playground вы получите предупреждение: «Код после возврата никогда не будет выполнен». Так что думаю #if #else #endif будет лучше.

DawnSong 10.11.2017 11:40

Это сработало для меня лучше всего

NSString *name = [[UIDevice currentDevice] name];


if ([name isEqualToString:@"iPhone Simulator"]) {

}

В Xcode 7.3 симулятор iPhone 6 Plus возвращает "iPhone".

Eric 11.05.2016 13:32

Быстро:

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

От Определите, создается ли приложение для устройства или симулятора в Swift

Чтобы различать приложения для Mac: #if (arch (i386) || arch (x86_64)) &&! Os (OSX) // мы находимся на симуляторе, работающем на Mac, а не в приложении для Mac. (Для кросс-платформенного кода, включенного в цели Mac)

Bobjt 22.10.2016 00:01

Кто-нибудь считал предоставленный ответ здесь?

Я полагаю, что эквивалент objective-c будет

+ (BOOL)isSimulator {
    NSOperatingSystemVersion ios9 = {9, 0, 0};
    NSProcessInfo *processInfo = [NSProcessInfo processInfo];
    if ([processInfo isOperatingSystemAtLeastVersion:ios9]) {
        NSDictionary<NSString *, NSString *> *environment = [processInfo environment];
        NSString *simulator = [environment objectForKey:@"SIMULATOR_DEVICE_NAME"];
        return simulator != nil;
    } else {
        UIDevice *currentDevice = [UIDevice currentDevice];
        return ([currentDevice.model rangeOfString:@"Simulator"].location != NSNotFound);
    }
}

/// Возвращает истину, если это симулятор, а не устройство

public static var isSimulator: Bool {
    #if (arch(i386) || arch(x86_64)) && os(iOS)
        return true
    #else
        return false
    #endif
}

ЕСТЬ ЛУЧШИЙ СПОСОБ!

Начиная с Xcode 9.3 beta 4, вы можете использовать #if targetEnvironment(simulator) для проверки.

#if targetEnvironment(simulator)
//Your simulator code
#endif

ОБНОВИТЬ
Xcode 10 и iOS 12 SDK тоже поддерживают это.

Это единственное, что у меня работает, остальные решения не работали.

Vrutin Rathod 17.05.2018 18:59

Примечание. Это только в быстром темпе.

Matt S. 01.05.2020 06:16

С Swift 4.2 (Xcode 10) мы можем это сделать

#if targetEnvironment(simulator)
  //simulator code
#else 
  #warning("Not compiling for simulator")
#endif

Просто еще одна копия вставки

J. Doe 09.11.2018 15:03

Apple добавила поддержку проверки того, что приложение предназначено для симулятора, со следующим:

#if targetEnvironment(simulator)
let DEVICE_IS_SIMULATOR = true
#else
let DEVICE_IS_SIMULATOR = false
#endif

Работает для Swift 5 и Xcode 12

Используйте этот код:

#if targetEnvironment(simulator)
   // Simulator
#else
   // Device
#endif

если ничего не сработало, попробуйте это

public struct Platform {

    public static var isSimulator: Bool {
        return TARGET_OS_SIMULATOR != 0 // Use this line in Xcode 7 or newer
    }

}

Для Swift 4.2 / xCode 10

Я создал расширение для UIDevice, поэтому могу легко узнать, запущен ли симулятор.

// UIDevice+CheckSimulator.swift

import UIKit

extension UIDevice {

    /// Checks if the current device that runs the app is xCode's simulator
    static func isSimulator() -> Bool {        
        #if targetEnvironment(simulator)
            return true
        #else
            return false
        #endif
    }
}

Например, в моем AppDelegate я использую этот метод, чтобы решить, необходима ли регистрация для удаленного уведомления, что невозможно для симулятора.

// CHECK FOR REAL DEVICE / OR SIMULATOR
if UIDevice.isSimulator() == false {

    // REGISTER FOR SILENT REMOTE NOTIFICATION
    application.registerForRemoteNotifications()
}

Другие вопросы по теме