Question #ifdef remplacement dans la langue Swift


En C / C ++ / Objective-C vous pouvez définir une macro en utilisant des préprocesseurs de compilateur. De plus, vous pouvez inclure / exclure certaines parties du code en utilisant des préprocesseurs de compilateur.

#ifdef DEBUG
    // Debug-only code
#endif

Existe-t-il une solution similaire dans Swift?


574
2018-06-02 21:06


origine


Réponses:


Oui tu peux le faire.

Dans Swift, vous pouvez toujours utiliser les macros du préprocesseur "# if / # else / # endif" (bien que plus contraignantes), selon Apple docs. Voici un exemple:

#if DEBUG
    let a = 2
#else
    let a = 3
#endif

Maintenant, vous devez définir le symbole "DEBUG" ailleurs. Réglez-le dans la section "Compilateur rapide - Drapeaux personnalisés", ligne "Autres drapeaux rapides". Vous ajoutez le symbole DEBUG avec le -D DEBUG entrée.

Comme d'habitude, vous pouvez définir une valeur différente dans Debug ou dans Release.

Je l'ai testé en code réel et ça fonctionne; il ne semble pas être reconnu dans une cour de récréation cependant.

Vous pouvez lire mon message original ici.


NOTE IMPORTANTE:  -DDEBUG=1 ne fonctionne pas. Seulement -D DEBUG travaux. Il semble que le compilateur ignore un indicateur avec une valeur spécifique.


858
2018-06-11 00:01



Comme indiqué dans Apple Docs

Le compilateur Swift n'inclut pas de préprocesseur. Au lieu de cela, il profite des attributs de compilation, des configurations de construction et des fonctionnalités de langage pour accomplir la même fonctionnalité. Pour cette raison, les directives du préprocesseur ne sont pas importées dans Swift.

J'ai réussi à réaliser ce que je voulais en utilisant des configurations de construction personnalisées:

  1. Accédez à votre projet / sélectionnez votre cible / Paramètres de construction / recherche de drapeaux personnalisés
  2. Pour la cible choisie, définissez votre indicateur personnalisé en utilisant le préfixe -D (sans espaces blancs), pour Debug et Release
  3. Faites les étapes ci-dessus pour chaque cible que vous avez

Voici comment vous vérifiez la cible:

#if BANANA
    print("We have a banana")
#elseif MELONA
    print("Melona")
#else
    print("Kiwi")
#endif

enter image description here

Testé avec Swift 2.2


287
2018-04-08 14:57



Dans de nombreuses situations, vous n'avez pas vraiment besoin de conditionnel compilation; vous avez juste besoin de conditionnel comportement que vous pouvez allumer et éteindre. Pour cela, vous pouvez utiliser une variable d'environnement. Cela a l'énorme avantage que vous n'avez pas vraiment à recompiler.

Vous pouvez définir la variable d'environnement et l'activer ou la désactiver facilement dans l'éditeur de schéma:

enter image description here

Vous pouvez récupérer la variable d'environnement avec NSProcessInfo:

    let dic = NSProcessInfo.processInfo().environment
    if dic["TRIPLE"] != nil {
        // ... do secret stuff here ...
    }

Voici un exemple concret. Mon application fonctionne uniquement sur l'appareil, car elle utilise la bibliothèque musicale, qui n'existe pas sur le simulateur. Comment, alors, prendre des captures d'écran sur le simulateur pour les appareils que je ne possède pas? Sans ces captures d'écran, je ne peux pas soumettre à l'AppStore.

j'ai besoin fausses données et un manière différente de le traiter. J'ai deux variables d'environnement: une qui, lorsqu'elle est activée, indique à l'application de générer les fausses données à partir des données réelles en cours d'exécution sur mon appareil; l'autre qui, lorsqu'il est allumé, utilise les fausses données (pas la bibliothèque musicale manquante) lors de l'exécution sur le simulateur. Activer / désactiver chacun de ces modes spéciaux est facile grâce aux cases à cocher des variables d'environnement dans l'éditeur Scheme. Et le bonus est que je ne peux pas les utiliser accidentellement dans ma construction App Store, car l'archivage n'a pas de variables d'environnement.


145
2018-06-21 18:13



Un changement majeur de ifdef remplacement est venu avec Xcode 8. i.e utilisation de Conditions de compilation actives.

Faire référence à Construire et relier dans Xcode 8 Note de publication.

Nouveaux paramètres de construction

Nouveau paramètre: SWIFT_ACTIVE_COMPILATION_CONDITIONS

“Active Compilation Conditions” is a new build setting for passing conditional compilation flags to the Swift compiler.

Auparavant, nous devions déclarer vos drapeaux de compilation conditionnelle sous OTHER_SWIFT_FLAGS, en rappelant de préfixer "-D" au paramètre. Par exemple, pour compiler sous condition avec une valeur MYFLAG:

#if MYFLAG1
    // stuff 1
#elseif MYFLAG2
    // stuff 2
#else
    // stuff 3
#endif

La valeur à ajouter au paramètre -DMYFLAG

Maintenant nous avons seulement besoin de passer la valeur MYFLAG au nouveau paramètre. Il est temps de déplacer toutes ces valeurs de compilation conditionnelles!

Veuillez vous référer au lien ci-dessous pour plus de fonctionnalités de configuration rapide dans Xcode 8: http://www.miqu.me/blog/2016/07/31/xcode-8-new-build-settings-and-analyzer-improvements/


119
2017-09-11 10:57



Xcode 8 et plus

Utilisation Conditions de compilation actives mettre en Paramètres de construction / compilateur Swift - Drapeaux personnalisés.

  • C'est le nouveau paramètre de construction pour passer des indicateurs de compilation conditionnelle au compilateur Swift.
  • Ajoutez des drapeaux simples comme ceci: ALPHA, BETA etc.

Ensuite, vérifiez avec conditions de compilation comme ça:

#if ALPHA
    //
#elseif BETA
    //
#else
    //
#endif

Astuce: Vous pouvez également utiliser #if !ALPHA etc.


73
2018-01-13 10:26



À partir de Swift 4.1, si tout ce dont vous avez besoin est juste de vérifier si le code est construit avec la configuration de débogage ou de libération, vous pouvez utiliser les fonctions intégrées:

  • _isDebugAssertConfiguration() (true lorsque l'optimisation est définie sur -Onone)
  • _isReleaseAssertConfiguration() (true lorsque l'optimisation est définie sur -O) (non disponible sur Swift 3+)
  • _isFastAssertConfiguration() (true lorsque l'optimisation est définie sur -Ounchecked)

par exemple.

func obtain() -> AbstractThing {
    if _isDebugAssertConfiguration() {
        return DecoratedThingWithDebugInformation(Thing())
    } else {
        return Thing()
    }
}

Par rapport aux macros préprocesseur,

  • ✓ Vous n'avez pas besoin de définir une coutume -D DEBUG drapeau pour l'utiliser
  • ~ Il est en fait défini en termes de paramètres d'optimisation, pas de configuration de construction Xcode
  • ✗ Non documenté, ce qui signifie que la fonction peut être supprimée dans n'importe quelle mise à jour (mais elle doit être sûre pour l'AppStore puisque l'optimiseur les transformera en constantes)

  • ✗ L'utilisation de if / else génère toujours un avertissement "Ne sera jamais exécuté".


73
2017-12-30 15:43



Il n'y a pas de préprocesseur Swift. (D'une part, la substitution de code arbitraire brise la sécurité de type et de mémoire.)

Cependant, Swift inclut des options de configuration au moment de la construction, de sorte que vous pouvez conditionnellement inclure du code pour certaines plates-formes ou styles de construction ou en réponse aux indicateurs que vous définissez avec -D arguments du compilateur. Contrairement à C, cependant, une section conditionnellement compilée de votre code doit être syntaxiquement complète. Il y a une section à ce sujet dans Utiliser Swift avec du cacao et Objective-C.

Par exemple:

#if os(iOS)
    let color = UIColor.redColor()
#else
    let color = NSColor.redColor()
#endif

70
2018-06-02 21:17



Mes deux cents pour Xcode 8:

a) Un drapeau personnalisé utilisant le -D préfixe fonctionne bien, mais ...

b) Une utilisation plus simple:

Dans Xcode 8, il y a une nouvelle section: "Conditions de compilation actives",  déjà avec deux lignes, pour le débogage et la libération.

Ajoutez simplement votre définition SANS -D.


39
2017-09-04 07:29



Constante isDebug basée sur les conditions de compilation active

Une autre solution, peut-être plus simple, qui se traduit toujours par un booléen que vous pouvez passer dans des fonctions sans poivrer #ifconditionnels tout au long de votre code est de définir DEBUG comme l'un de vos projets de construction de cibles Active Compilation Conditions et inclure les éléments suivants (je le définis comme une constante globale):

#if DEBUG
    let isDebug = true
#else
    let isDebug = false
#endif

Constante isDebug basée sur les paramètres d'optimisation du compilateur

Ce concept s'appuie sur La réponse de kennytm

Le principal avantage par rapport à kennytm est que cela ne dépend pas de méthodes privées ou non documentées.

Dans Swift 4:

let isDebug: Bool = {
    var isDebug = false
    // function with a side effect and Bool return value that we can pass into assert()
    func set(debug: Bool) -> Bool {
        isDebug = debug
        return isDebug
    }
    // assert:
    // "Condition is only evaluated in playgrounds and -Onone builds."
    // so isDebug is never changed to true in Release builds
    assert(set(debug: true))
    return isDebug
}()

Par rapport aux macros préprocesseur et la réponse de kennytm,

  • ✓ Vous n'avez pas besoin de définir une coutume -D DEBUG drapeau pour l'utiliser
  • ~ Il est en fait défini en termes de paramètres d'optimisation, pas de configuration de construction Xcode
  • Documenté, ce qui signifie que la fonction suivra les modèles normaux de libération / dépréciation de l'API.

  • ✓ Utiliser dans si / sinon ne pas générer un avertissement "Ne sera jamais exécuté".


25
2017-11-22 20:41