En Objective-C, nous pouvons savoir si une application est en cours de création pour un appareil ou un simulateur à l'aide de macros:
#if TARGET_IPHONE_SIMULATOR
// Simulator
#else
// Device
#endif
Ce sont des macros à la compilation et non disponibles au moment de l'exécution.
Comment puis-je obtenir la même chose dans Swift? J'ai cherché un débordement de pile, jeté un coup d’œil dans la documentation et je ne peux pas le comprendre.
Bien que cette réponse puisse fonctionner, la solution recommandée pour une vérification statique (comme le précisent plusieurs ingénieurs Apple) consiste à définir un indicateur de compilateur personnalisé ciblant les simulateurs iOS. Pour des instructions détaillées sur la marche à suivre, voir Réponse de @ mbelsky .
Si vous avez besoin d’une vérification statique (par exemple, pas un runtime si/else), vous ne pouvez pas détecter le simulateur directement, mais vous pouvez détecter iOS sur une architecture de bureau comme suit:
#if (Arch(i386) || Arch(x86_64)) && os(iOS)
...
#endif
Après la version Swift 4.1
Dernière utilisation, maintenant directement pour tous dans une condition pour tous les types de simulateurs doivent appliquer une seule condition -
#if targetEnvironment(simulator)
// your simulator code
#else
// your real device code
#endif
Pour plus de précisions, vous pouvez vérifier Swift proposition SE-0190
Pour les anciennes versions -
Clairement, ceci est false sur un périphérique, mais renvoie true pour le simulateur iOS, comme spécifié dans la documentation :
La configuration de génération Arch (i386) renvoie true lorsque le code est compilé pour le simulateur iOS 32 bits.
Si vous développez pour un simulateur autre que iOS, vous pouvez simplement faire varier le paramètre os
: par exemple.
Détecter le simulateur watchOS
#if (Arch(i386) || Arch(x86_64)) && os(watchOS)
...
#endif
Détecter le simulateur tvOS
#if (Arch(i386) || Arch(x86_64)) && os(tvOS)
...
#endif
Ou même détecter n'importe quel simulateur
#if (Arch(i386) || Arch(x86_64)) && (os(iOS) || os(watchOS) || os(tvOS))
...
#endif
Si, au contraire, vous êtes d'accord avec une vérification à l'exécution, vous pouvez inspecter la variable TARGET_OS_SIMULATOR
(ou TARGET_IPHONE_SIMULATOR
sous iOS 8 et inférieur), qui est la vérité sur un simulateur.
Veuillez noter que ceci est différent et légèrement plus limité que l’utilisation d’un indicateur de préprocesseur. Par exemple, vous ne pourrez pas l'utiliser à la place d'un if/else
incorrect du point de vue de la syntaxe (par exemple, en dehors de l'étendue des fonctions).
Dites, par exemple, que vous souhaitez avoir différentes importations sur l'appareil et sur le simulateur. Ceci est impossible avec une vérification dynamique, alors que c'est trivial avec une vérification statique.
#if (Arch(i386) || Arch(x86_64)) && os(iOS)
import Foo
#else
import Bar
#endif
De plus, étant donné que l'indicateur est remplacé par un 0
ou un 1
par le préprocesseur Swift, si vous l'utilisez directement dans une expression if/else
, le compilateur émet un avertissement concernant le code inaccessible.
Pour contourner cet avertissement, reportez-vous à l'une des autres réponses.
OUTDATED FOR Swift 4.1. Utilisez #if targetEnvironment(simulator)
à la place. La source
Pour détecter le simulateur dans Swift, vous pouvez utiliser la configuration de construction:
Maintenant, vous pouvez utiliser cette instruction pour détecter le simulateur:
#if IOS_SIMULATOR
print("It's an iOS Simulator")
#else
print("It's a device")
#endif
Aussi, vous pouvez étendre la classe UIDevice:
extension UIDevice {
var isSimulator: Bool {
#if IOS_SIMULATOR
return true
#else
return false
#endif
}
}
// Example of usage: UIDevice.current.isSimulator
Info mise à jour au 20 février 2018
Il semble que @russbishop ait une réponse faisant autorité qui rend cette réponse "incorrecte" - même si elle a semblé fonctionner longtemps.
Réponse précédente
Sur la base de la réponse de @ WZW et des commentaires de @ Pang, j'ai créé une structure d'utilitaire simple. Cette solution évite les avertissements produits par la réponse de @ WZW.
import Foundation
struct Platform {
static var isSimulator: Bool {
return TARGET_OS_SIMULATOR != 0
}
}
Exemple d'utilisation:
if Platform.isSimulator {
print("Running on Simulator")
}
À partir de Xcode 9.3
#if targetEnvironment(simulator)
Swift prend en charge une nouvelle condition de plate-forme targetEnvironment avec un simulateur d'argument valide unique. Compilation conditionnelle du formulaire '#if targetEnvironment (simulator)' peut maintenant être utilisé pour détecter quand la cible de construction est un simulateur. Le compilateur Swift va tenter de détecter, avertir et suggérer l’utilisation de targetEnvironment (simulateur) lorsque évaluer les conditions de la plate-forme qui semblent être en train de tester le simulateur environnements indirectement, via les plates-formes os () et Arch () existantes conditions. (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
}
}
Avant iOS 9:
extension UIDevice {
static var isSimulator: Bool {
return UIDevice.currentDevice().model == "iPhone Simulator"
}
}
Objectif 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
Vous pouvez maintenant utiliser targetEnvironment(simulator)
comme argument.
#if targetEnvironment(simulator)
// Simulator
#else
// Device
#endif
Mise à jour pour Xcode 9.3
Permettez-moi de clarifier certaines choses ici:
TARGET_OS_SIMULATOR
n'est pas défini dans le code Swift dans de nombreux cas; vous pouvez être importé accidentellement à cause d'un en-tête de pontage, mais ceci est fragile et n'est pas pris en charge. Ce n'est pas même possible dans les cadres. C'est pourquoi certaines personnes ne savent pas si cela fonctionne dans Swift.Pour effectuer des contrôles dynamiques:
Vérifier ProcessInfo.processInfo.environment["SIMULATOR_DEVICE_NAME"] != nil
est parfaitement correct.
Vous pouvez également simuler le modèle sous-jacent en cochant SIMULATOR_MODEL_IDENTIFIER
qui renverra des chaînes comme iPhone10,3
.
Pour effectuer des contrôles statiques:
Xcode 9.2 et versions antérieures: définissez votre propre drapeau de compilation Swift (comme indiqué dans les autres réponses).
Xcode 9.3+ utilise la nouvelle condition targetEnvironment:
#if targetEnvironment(simulator)
// for sim only
#else
// for device
#endif
Ce qui fonctionne pour moi depuis que Swift 1.0 recherche une architecture autre qu'armer:
#if Arch(i386) || Arch(x86_64)
//simulator
#else
//device
#endif
Runtime, mais plus simple que la plupart des autres solutions ici:
if TARGET_OS_SIMULATOR != 0 {
// target is current running in the simulator
}
Sinon, vous pouvez simplement appeler une fonction d'assistance Objective-C qui renvoie un booléen utilisant la macro de préprocesseur (surtout si vous êtes déjà en train de mixer dans votre projet).
Edit: Pas la meilleure solution, surtout à partir de Xcode 9.3. Voir Réponse de HotJard
Dans les systèmes modernes:
#if targetEnvironment(simulator)
// sim
#else
// device
#endif
C'est facile.
TARGET_IPHONE_SIMULATOR
est obsolète dans iOS 9. TARGET_OS_SIMULATOR
est le remplacement. De plus, TARGET_OS_EMBEDDED
est disponible.
De 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 */
Dans Xcode 7.2 (et plus tôt, mais je n'ai pas testé beaucoup plus tôt), vous pouvez définir un indicateur de construction spécifique à la plate-forme "-D TARGET_IPHONE_SIMULATOR" pour "Any iOS Simulator".
Recherchez dans les paramètres de construction du projet sous "Compilateur Swift - Indicateurs client", puis activez le drapeau dans "Autres drapeaux Swift". Vous pouvez définir un indicateur spécifique à la plate-forme en cliquant sur l'icône "plus" lorsque vous passez la souris sur une configuration de construction.
Cela présente quelques avantages: 1) Vous pouvez utiliser le même test conditionnel ("#if TARGET_IPHONE_SIMULATOR") dans votre code Swift et Objective-C. 2) Vous pouvez compiler des variables qui ne s'appliquent qu'à chaque construction.
Toutes décrites ici 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
J'ai utilisé ce code ci-dessous dans Swift 3
if TARGET_IPHONE_SIMULATOR == 1 {
//simulator
} else {
//device
}
Actuellement, je préfère utiliser la classe ProcessInfo pour savoir si le périphérique est un simulateur et quel type de périphérique est utilisé:
if let simModelCode = ProcessInfo().environment["SIMULATOR_MODEL_IDENTIFIER"] {
print("yes is a simulator :\(simModelCode)")
}
Mais, comme vous le savez, simModelCode
n'est pas un code confortable pour comprendre immédiatement quel type de simulateur a été lancé. Si vous en avez besoin, vous pouvez essayer de voir cet autre SO answer pour déterminer le iPhone actuel/device et d’avoir une chaîne plus lisible par l’homme.
J'espère que cette extension sera utile
extension UIDevice {
static var isSimulator: Bool = {
var isSimulator = false
#if targetEnvironment(simulator)
isSimulator = true
#endif
return isSimulator
}()
}
Usage:
if UIDevice.isSimulator {
print("running on simulator")
}
Utilisez ce code ci-dessous:
#if targetEnvironment(simulator)
// Simulator
#else
// Device
#endif
Fonctionne pour Swift 4
et Xcode 9.4.1