Як я можу програмно визначити, чи працює моя програма в тренажері iphone?


270

Як йдеться в запитанні, я хотів би головним чином знати, чи працює мій код у тренажері чи ні, але я також зацікавився б знати конкретну версію iphone, яка працює або моделюється.

РЕДАКТУВАННЯ: Я додав слово "програмно" до назви питання. Суть мого питання полягає в тому, щоб мати можливість динамічно включати / виключати код залежно від того, яка версія / симулятор працює, тому я б дійсно шукав щось на зразок директиви перед процесором, яка може надати мені цю інформацію.


Я не впевнений, що директива перед процесором є динамічною (хоча це все одно, що ви шукали). Директива означає, що ви насправді знали, коли будували її, куди вона буде заводитися.
WiseOldDuck

Відповіді:


356

Вже запитували, але з зовсім іншою назвою.

Які #defines встановлюються за допомогою Xcode під час компіляції для iPhone

Я повторю свою відповідь звідти:

Це в документах SDK у розділі "Умовно складання вихідного коду"

Відповідне визначення - TARGET_OS_SIMULATOR, яке визначено в /usr/include/TargetConditionss.h в рамках iOS. На попередніх версіях ланцюжка інструментів вам довелося написати:

#include "TargetConditionals.h"

але це більше не потрібно в поточному (Xcode 6 / iOS8) інструментальному ланцюжку.

Так, наприклад, якщо ви хочете перевірити, чи працює ви на пристрої, вам слід зробити це

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

залежно від того, що підходить для вашого використання.


1
Дякую. Я згоден з вами, це більш конкретна версія вашого оригінального питання. Якби ваш прийшов у моєму первісному пошуку, я б навіть не потребував просити.
Джеффрі Мейєр

5
Будьте уважні до цих визначень. Під час компіляції коду з пункту меню "Проект> Встановити активний SDK> Симулятор ...", як TARGET_IPHONE_SIMULATOR як TARGET_OS_IPHONE змінні обидва визначені! Тож єдиний правильний спосіб відокремити логіку вказаний нижче Пітом («Спасибі чувак»).
Вадим

5
Слідкуйте за різницею #if та #ifdef. Для мене це стало причиною неправильної поведінки.
Антон

7
Можливо, необхідність включення TargetConditionss була усунена, оскільки це було написано, але просто хотілося зазначити, що #if TARGET_IPHONE_SIMULATOR працює без включення TargetConditionss.h зараз.
dmur

1
@Dimitris Це хороша практика. Ви не знаєте, як визначено TARGET_OS_SIMULATOR, так що! (TARGET_OS_SIMULATOR) може бути не тотожним! TARGET_OS_SIMULATOR
Airsource Ltd,

106

Оновлений код:

Це спрямовано на роботу офіційно.

#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

7
Як і для iOS 8 та Xcode 6.1.1, TARGET_OS_IPHONE відповідає симулятору.
маль

3
це більше не переживає нові версії
XCode

1
Якщо ви не перебуваєте у 2016 році та не запускаєте 64-бітовий симулятор. Або в 2019 році та запустіть свій код на iPhone з процесором Intel.
gnasher729

61

Не директива перед процесором, але саме це я шукав, коли прийшов до цього питання;

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

9
[model compare:iPhoneSimulator] == NSOrderedSameмає бути написано як[model isEqualToString:iPhoneSimulator]
user102008

18
Або [model hasSuffix:@"Simulator"]якщо ви дбаєте лише про "симулятор" взагалі, а не iPhone чи iPad зокрема. Ця відповідь не буде працювати для симулятора iPad :)
Nuthatch

Оновлений тому, що коментар Нутчача робить це найкращою відповіддю в тото.
Le Mot Juiced

12
В iOS9 перевірте пристрій nameзамістьmodel
n.Drake

1
Код не працюватиме, якщо користувач додасть Simulatorслово у своє ім’я пристрою
mbelsky

55

Найкращий спосіб зробити це:

#if TARGET_IPHONE_SIMULATOR

і ні

#ifdef TARGET_IPHONE_SIMULATOR

оскільки його завжди визначено: 0 або 1


39

ТАКИЙ ЛИШИЙ ШЛЯХ ЗАРАЗ!

Станом на Xcode 9.3 beta 4 ви можете використовувати #if targetEnvironment(simulator)для перевірки.

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

UPDATE
Xcode 10 і iOS 12 SDK також підтримують це.


1
Це єдине, що працює для мене, інші рішення не спрацювали.
Врутін Ратод

Примітка. Це лише швидко.
Метт С.

35

У випадку 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. Допоміг мені подолати дивну помилку пристрою та симулятора в основних даних. Ти людина!
Залізний Джон Бонні

5
У Playground ви отримаєте попередження: "Код після" повернення "ніколи не буде виконаний". Тому я думаю, #if #else #endifбуде краще.
DawnSong


9

Усі ці відповіді хороші, але це якимось чином бентежить новачків, як я, оскільки не уточнює перевірку компіляції та перевірку часу виконання. Попередній переробник знаходиться до часу компіляції, але нам слід зробити це більш зрозумілим

Ця стаття в блозі показує, як виявити симулятор 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

1
Як це покращується в інших відповідях?
користувач151019

@Mark Це трохи уточнює
onmyway133

5
Наразі в Xcode 7, iOS 9 Simulator [[UIDevice currentDevice] model]повертається iPhoneтакож замість iPhone Simulator. Отже, я вважаю, що це не найкращий підхід.
eMdOS

6

Попередні відповіді трохи датовані. Я виявив, що все, що вам потрібно зробити, це запитувати TARGET_IPHONE_SIMULATORмакрос ( не потрібно включати жодні інші файли заголовків (якщо вважати, що ви кодуєте iOS)).

Я намагався, TARGET_OS_IPHONEале він повернув те саме значення (1) під час роботи на фактичному пристрої та симуляторі, тому я рекомендую TARGET_IPHONE_SIMULATORзамість цього використовувати .


TARGET_OS_IPHONE - це код, який може працювати на iOS або MacOS X. Очевидно, ви хочете, щоб цей код поводився так, як "iPhone" на тренажері.
gnasher729

6

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

4

У мене були одні TARGET_IPHONE_SIMULATORі ті ж проблеми, і TARGET_OS_IPHONEвони завжди визначені, і вони встановлені на 1. Рішення Піта, звичайно, працює, але якщо ви коли-небудь траплятиметеся будувати щось інше, ніж інтелект (навряд чи, але хто знає), ось щось безпечне, як доки апаратне забезпечення 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_*константи визначені правильно.


4

Хтось вважав відповідь, надану тут ?

Я припускаю, що це було б еквівалентом цілі-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);
    }
}

4

Для 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()
}

1

Включити всі типи "тренажерів"

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

4
Це не має нічого спільного з Xcode 7. Якщо ви запускаєте iOS Simulator з iOS8 (з Xcode 7), це працюватиме. Він не буде працювати для iOS9, де [[модель UIDevice currentDevice]] повертає лише "iPhone", якщо додаток було запущено з iOS Simulator
tesla

чому ні -[NSString containsString]?
Гобє

1

За допомогою Swift 4.2 (Xcode 10) ми можемо це зробити

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

1
Ще одна копія пасти
J. Doe

0

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

Це для мене працювало:

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

1
Код не буде працювати, якщо користувач додасть Simulatorслово у своє ім'я пристрою
mbelsky

На жаль, XCode 8 UIDevice.current.nameповідомляє назву машини, на якій працює Симулятор (як правило, щось на зразок "MacBook Pro Simon"), тому тест став ненадійним. Я все ще шукаю чистий спосіб виправити це.
Майкл

0

/// Повертає true, якщо його симулятор, а не пристрій

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

0

Apple додала підтримку для перевірки, що додаток орієнтовано на тренажер із наступним:

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

0

якщо нічого не вийшло, спробуйте це

public struct Platform {

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

}

-4

На мою думку, відповідь (представлена ​​вище та повторена нижче):

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

є найкращою відповіддю, оскільки він, очевидно, виконується в RUNTIME порівняно з КОМПЛЕКТНОЇ ДИРЕКТИВОЮ.


11
Я не погоджуюсь. Цей код виявляється у вашому продукті, тоді як директива компілятора утримує - на пристрої непотрібне - розпорядок роботи.
дев’ять каменів

1
Директиви компілятора працюють, тому що пристрій і тренажери є абсолютно різними цілями компіляції - тобто ви б не використовували однаковий бінарний код для обох. Він повинен бути складений на інше обладнання, так що має сенс в тому випадку.
Бред Паркс

Виконання в RUNTIME дає найгіршу можливу відповідь.
gnasher729

-4

Це працювало для мене найкраще

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


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

}

2
На Xcode 7.3 повертається iPhone 6 Plus Simulator "iPhone".
Ерік
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.