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

StackOverflow https://stackoverflow.com/questions/458304

Вопрос

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

РЕДАКТИРОВАТЬ:Я добавил слово «программно» к названию вопроса.Суть моего вопроса заключается в том, чтобы иметь возможность динамически включать/исключать код в зависимости от того, какая версия/симулятор запущена, поэтому я бы действительно искал что-то вроде директивы препроцессора, которая могла бы предоставить мне эту информацию.

Это было полезно?

Решение

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

Что #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

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

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

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

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

#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

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

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

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

#if TARGET_IPHONE_SIMULATOR

а не

#ifdef TARGET_IPHONE_SIMULATOR

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

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

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

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

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

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

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

struct Platform {
    static let isSimulator: Bool = {
        #if arch(i386) || arch(x86_64)
            return true
        #endif
        return false
    }()
}

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

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

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

В этой статье блога показано Как обнаружить симулятор 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

Работает для Swift 4 и Xcode 9.4.1

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

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

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

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

У меня была одна и та же проблема, и 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_* определены правильно.

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

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

Я полагаю, что объективный эквивалент будет

+ (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);
    }
}

Включить все типы & "симуляторов "

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

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

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

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

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

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

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

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

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

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

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

public struct Platform {

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

}

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

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


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

}

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

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

- лучший ответ, потому что он явно выполняется в RUNTIME, а не является COMPILE DIRECTIVE.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top