it-swarm.com.de

Ermitteln Sie, ob in Swift eine App für ein Gerät oder einen Simulator erstellt wird

In Objective-C können wir wissen, ob eine App für ein Gerät oder einen Simulator mit Makros erstellt wird:

#if TARGET_IPHONE_SIMULATOR
    // Simulator
#else
    // Device
#endif

Dies sind Makros zur Kompilierungszeit, die zur Laufzeit nicht verfügbar sind.

Wie kann ich dasselbe in Swift erreichen? Ich habe den Stack-Überlauf gesucht, habe mir die Dokumente angesehen und kann es nicht herausfinden.

224
RaffAl

Update vom 30.01.19

Während diese Antwort möglicherweise funktioniert, ist die empfohlene Lösung für eine statische Überprüfung (von mehreren Apple-Ingenieuren klargestellt), ein benutzerdefiniertes Compiler-Flag für iOS-Simulatoren zu definieren. Ausführliche Anweisungen dazu finden Sie in der Antwort von @ mbelsky .

Ursprüngliche Antwort

Wenn Sie eine statische Überprüfung benötigen (z. B. keine Laufzeit, wenn/else), können Sie den Simulator nicht direkt erkennen, aber Sie können iOS auf einer Desktop-Architektur wie folgt erkennen

#if (Arch(i386) || Arch(x86_64)) && os(iOS)
    ...
#endif

Nach Swift 4.1 version

Neueste Verwendung, jetzt direkt für alle in einer Bedingung, für alle Arten von Simulatoren muss nur eine Bedingung angewendet werden -

#if targetEnvironment(simulator)
  // your simulator code
#else
  // your real device code
#endif

Zur weiteren Erläuterung können Sie Swift Vorschlag SE-0190überprüfen. _ 


Für ältere Version -

Natürlich ist dies auf einem Gerät falsch, aber es gibt den Wert für den iOS-Simulator zurück, wie in der Dokumentation angegeben :

Die Build-Konfiguration für Arch (i386) gibt true zurück, wenn der Code für den 32-Bit-iOS-Simulator kompiliert wird.

Wenn Sie für einen anderen Simulator als iOS entwickeln, können Sie einfach den Parameter os variieren: z.

Erkennen Sie den Simulator watchOS

#if (Arch(i386) || Arch(x86_64)) && os(watchOS)
...
#endif

Erkennen Sie den Simulator tvOS

#if (Arch(i386) || Arch(x86_64)) && os(tvOS)
...
#endif

Oder sogar any Simulator erkennen

#if (Arch(i386) || Arch(x86_64)) && (os(iOS) || os(watchOS) || os(tvOS))
...
#endif

Wenn Sie mit einer Laufzeitprüfung in Ordnung sind, können Sie die TARGET_OS_SIMULATOR-Variable (oder TARGET_IPHONE_SIMULATOR in iOS 8 und darunter) überprüfen, die auf einem Simulator wahr ist.

Bitte beachten Sie, dass dies anders und etwas eingeschränkter ist als die Verwendung eines Präprozessor-Flags. Zum Beispiel können Sie es nicht dort einsetzen, wo ein if/else syntaktisch ungültig ist (z. B. außerhalb von Funktionsbereichen).

Angenommen, Sie möchten verschiedene Importe auf dem Gerät und im Simulator haben. Dies ist bei einer dynamischen Prüfung nicht möglich, bei einer statischen Prüfung dagegen trivial.

#if (Arch(i386) || Arch(x86_64)) && os(iOS)
  import Foo
#else
  import Bar
#endif

Da das Flag durch den Swift-Präprozessor durch einen 0 oder einen 1 ersetzt wird, gibt der Compiler bei direkter Verwendung in einem if/else-Ausdruck eine Warnung vor nicht erreichbarem Code aus.

Um diese Warnung zu umgehen, lesen Sie eine der anderen Antworten.

273

OUTDATED FOR Swift 4.1. Verwenden Sie stattdessen #if targetEnvironment(simulator). Source

Um den Simulator in Swift zu erkennen, können Sie die Build-Konfiguration verwenden:

  • Definieren Sie diese Konfiguration - D IOS_SIMULATOR in Swift Compiler - Benutzerdefinierte Flags> Andere Swift Flags
  • Wählen Sie in diesem Dropdown-Menü Beliebiges iOS-Simulator-SDKDrop down list

Nun könnten Sie diese Anweisung verwenden, um den Simulator zu erkennen:

#if IOS_SIMULATOR
    print("It's an iOS Simulator")
#else
    print("It's a device")
#endif

Sie können auch die UIDevice-Klasse erweitern:

extension UIDevice {
    var isSimulator: Bool {
        #if IOS_SIMULATOR
            return true
        #else
            return false
        #endif
    }
}
// Example of usage: UIDevice.current.isSimulator
162
mbelsky

Aktualisierte Info vom 20. Februar 2018

Es sieht so aus, als ob @russbishop eine maßgebliche Antwort hat, die diese Antwort "falsch" macht - obwohl sie lange Zeit zu funktionieren schien.

Ermitteln, ob in Swift eine App für ein Gerät oder einen Simulator erstellt wird

Vorherige Antwort

Basierend auf der Antwort von @ WZW und den Kommentaren von @ Pang erstellte ich eine einfache Utility-Struktur. Diese Lösung vermeidet Warnungen, die von @ WZWs Antwort erzeugt werden.

import Foundation

struct Platform {

    static var isSimulator: Bool {
        return TARGET_OS_SIMULATOR != 0
    }

}

Verwendungsbeispiel:

if Platform.isSimulator {
    print("Running on Simulator")
}
153
Daniel

Ab Xcode 9.3

#if targetEnvironment(simulator)

Swift unterstützt eine neue Plattformbedingung targetEnvironment mit einer einzelner gültiger Argumentsimulator. Bedingte Kompilierung des Formulars '#if targetEnvironment (Simulator)' kann jetzt verwendet werden, um festzustellen, wann das Build-Ziel ein Simulator ist. Der Swift-Compiler versucht, Erkennen, warnen und die Verwendung von targetEnvironment (Simulator) vorschlagen, wenn Auswerten von Plattformbedingungen, die für den Simulator zu testen scheinen Umgebungen indirekt über die vorhandene os () - und Arch () - Plattform Bedingungen. (SE-0190)

iOS 9+:

extension UIDevice {
    static var isSimulator: Bool {
        return NSProcessInfo.processInfo().environment["SIMULATOR_DEVICE_NAME"] != nil
    }
}

Swift 3:

extension UIDevice {
    static var isSimulator: Bool {
        return ProcessInfo.processInfo.environment["SIMULATOR_DEVICE_NAME"] != nil
    }
}

Vor iOS 9:

extension UIDevice {
    static var isSimulator: Bool {
        return UIDevice.currentDevice().model == "iPhone Simulator"
    }
}

Ziel c:

@interface UIDevice (Additions)
- (BOOL)isSimulator;
@end

@implementation UIDevice (Additions)

- (BOOL)isSimulator {
    if([[NSProcessInfo processInfo] isOperatingSystemAtLeastVersion:(NSOperatingSystemVersion){9, 0, 0}]) {
        return [NSProcessInfo processInfo].environment[@"SIMULATOR_DEVICE_NAME"] != nil;
    } else {
        return [[self model] isEqualToString:@"iPhone Simulator"];
    }
}

@end
63
HotJard

Schnell 4

Sie können jetzt targetEnvironment(simulator) als Argument verwenden.

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

Aktualisiert für Xcode 9.3

48
Matt Swift

Lassen Sie mich hier einige Dinge klarstellen:

  1. TARGET_OS_SIMULATOR ist in vielen Fällen nicht im Swift-Code festgelegt. Sie könnten es aufgrund eines Überbrückungskopfs versehentlich importieren, dies ist jedoch spröde und wird nicht unterstützt. Es ist auch nicht einmal in Frameworks möglich. Deshalb sind einige Leute verwirrt, ob dies in Swift funktioniert.
  2. Ich rate dringend davon ab, Architektur als Ersatz für den Simulator zu verwenden.

So führen Sie dynamische Prüfungen durch:

ProcessInfo.processInfo.environment["SIMULATOR_DEVICE_NAME"] != nil zu überprüfen ist vollkommen in Ordnung.

Sie können das zugrundeliegende Modell, das simuliert wird, auch abrufen, indem Sie SIMULATOR_MODEL_IDENTIFIER überprüfen, wodurch Zeichenfolgen wie iPhone10,3 zurückgegeben werden.

So führen Sie statische Prüfungen durch:

Xcode 9.2 und früher: Definieren Sie Ihr eigenes Swift-Kompilierungsflag (wie in anderen Antworten gezeigt).

Xcode 9.3+ verwendet die neue Bedingung targetEnvironment:

#if targetEnvironment(simulator)
    // for sim only
#else
    // for device
#endif
26
russbishop

Was für mich seit Swift 1.0 funktioniert, sucht nach einer anderen Architektur als arm:

#if Arch(i386) || Arch(x86_64)

     //simulator
#else 
     //device

#endif
15
akaru

Laufzeit, aber einfacher als die meisten anderen Lösungen hier:

if TARGET_OS_SIMULATOR != 0 {
    // target is current running in the simulator
}

Alternativ können Sie einfach eine Objective-C-Hilfsfunktion aufrufen, die einen Boolean zurückgibt, der das Präprozessor-Makro verwendet (insbesondere, wenn Sie bereits in Ihrem Projekt gemischt haben).

Edit: Nicht die beste Lösung, besonders seit Xcode 9.3. Siehe HotJards Antwort

13
shim

In modernen Systemen:

#if targetEnvironment(simulator)
    // sim
#else
    // device
#endif

Es ist einfach.

9
Fattie

TARGET_IPHONE_SIMULATOR ist in iOS 9 veraltet. TARGET_OS_SIMULATOR ist der Ersatz. Auch TARGET_OS_EMBEDDED ist verfügbar.

Von TargetConditionals.h :

#if defined(__GNUC__) && ( defined(__Apple_CPP__) || defined(__Apple_CC__) || defined(__MACOS_CLASSIC__) )
. . .
#define TARGET_OS_SIMULATOR         0
#define TARGET_OS_EMBEDDED          1 
#define TARGET_IPHONE_SIMULATOR     TARGET_OS_SIMULATOR /* deprecated */
#define TARGET_OS_NANO              TARGET_OS_WATCH /* deprecated */ 
5
Nuthatch

In Xcode 7.2 (und früher, aber ich habe nicht getestet, wie viel früher), können Sie ein plattformspezifisches Build-Flag "-D TARGET_IPHONE_SIMULATOR" für "Any iOS Simulator" setzen.

Schauen Sie in den Projekterstellungseinstellungen unter "Swift-Compiler - Kundenflags" nach und setzen Sie das Flag in "Andere Swift-Flags". Sie können ein plattformspezifisches Flag setzen, indem Sie auf das Plus-Symbol klicken, wenn Sie mit der Maus über eine Build-Konfiguration fahren.

Es gibt einige Vorteile, wenn Sie dies auf diese Weise tun: 1) Sie können denselben bedingten Test ("#if TARGET_IPHONE_SIMULATOR") in Ihrem Swift- und Objective-C-Code verwenden. 2) Sie können Variablen kompilieren, die nur für jeden Build gelten.

Xcode Build-Einstellungen Screenshot

3
xgerrit

Alle hier beschriebenen 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

2
dimpiax

Ich habe diesen Code in Swift 3 verwendet

if TARGET_IPHONE_SIMULATOR == 1 {
    //simulator
} else {
    //device
}
1
ak_ninan

Schnell 4:

Derzeit ziehe ich es vor, die Klasse ProcessInfo zu verwenden, um zu wissen, ob das Gerät ein Simulator ist und welche Art von Gerät verwendet wird:

if let simModelCode = ProcessInfo().environment["SIMULATOR_MODEL_IDENTIFIER"] {
            print("yes is a simulator :\(simModelCode)")
}

Wie Sie wissen, ist simModelCode kein bequemer Code, um sofort zu verstehen, welche Art von Simulator gestartet wurde. Wenn Sie also brauchen, können Sie versuchen, mit diesem anderen SO answer das aktuelle iPhone zu ermitteln/Gerätemodell und eine besser lesbare Zeichenfolge.

1

Ich hoffe, diese Erweiterung ist praktisch

extension UIDevice {
    static var isSimulator: Bool = {
        var isSimulator = false
        #if targetEnvironment(simulator)
        isSimulator = true
        #endif
        return isSimulator
    }()
}

Verwendungszweck:

if UIDevice.isSimulator {
    print("running on simulator")
}
1
Lucas Chwe

Verwenden Sie den folgenden Code:

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

Funktioniert für Swift 4 und Xcode 9.4.1

0
Haroldo Gondim