821 votes

Remplacement des #ifdef dans le langage Swift

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

#ifdef DEBUG
    // Debug-only code
#endif

Existe-t-il une solution similaire en Swift ?

1 votes

Comme idée, vous pourriez mettre ceci dans vos en-têtes de pontage obj-c..

60 votes

Vous devriez vraiment attribuer une réponse car vous avez le choix entre plusieurs réponses et cette question vous a valu beaucoup de votes positifs.

0 votes

@Userthatisnotauser vous avez totalement manqué le point. Vous posez une question, vous obtenez de bonnes réponses - choisissez-en une. N'ignorez pas le temps et l'effort.

1165voto

Jean Le Moignan Points 2364

Oui, vous pouvez le faire.

Dans Swift, vous pouvez toujours utiliser les macros du préprocesseur "#if/#else/#endif" (bien que cela soit plus contraignant), comme suit Documents d'Apple . Voici un exemple :

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

Maintenant, vous devez définir le symbole "DEBUG" ailleurs, cependant. Définissez-le dans la section "Swift Compiler - Custom Flags", ligne "Other Swift Flags". Vous ajoutez le symbole DEBUG avec la commande -D DEBUG l'entrée.

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

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

Vous pouvez lire mon message original aquí .


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

45 votes

C'est la bonne réponse, bien qu'il faille noter que vous pouvez seulement vérifier la présence du drapeau mais pas une valeur spécifique.

0 votes

Eh bien, c'est désagréable. J'utilise fréquemment #if 0/#else/#endif pour tester du code. Cela rend trivial le fait d'aller et venir pour tester des choses comme la durabilité ou la vitesse. Je comprends que le préprocesseur était juste un autre hack (sur un hack sur un hack). Mais dans ce cas, c'était vraiment une chose utile®.

22 votes

Note supplémentaire : En plus d'ajouter -D DEBUG comme indiqué ci-dessus, vous devez également définir DEBUG=1 en Apple LLVM 6.0 - Preprocessing -> Preprocessor Macros .

384voto

Andrej Points 4971

Comme indiqué dans Apple Docs

Le compilateur Swift ne comprend pas de préprocesseur. Au lieu de cela, il tire parti des attributs de compilation, des configurations de construction et des caractéristiques du langage pour accomplir la même fonctionnalité. C'est pourquoi les directives de préprocesseur ne sont pas importées dans Swift.

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

  1. Allez dans votre projet / sélectionnez votre cible / Build Settings / recherchez Custom Flags
  2. Pour votre cible choisie, définissez votre drapeau 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 vérifier 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

183voto

matt Points 60113

Dans de nombreuses situations, vous n'avez pas vraiment besoin du conditionnel. compilation ; vous avez juste besoin du conditionnel comportement que vous pouvez allumer et éteindre. Pour cela, vous pouvez utiliser une variable d'environnement. Cela présente l'énorme avantage de ne pas avoir à 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 ne fonctionne que sur l'appareil, car elle utilise la bibliothèque musicale, qui n'existe pas sur le simulateur. Comment, alors, faire des captures d'écran sur le simulateur pour des appareils que je ne possède pas ? Sans ces captures d'écran, je ne peux pas soumettre mon application à l'AppStore.

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

0 votes

Pour une raison quelconque, ma variable d'environnement est revenue à zéro au deuxième lancement de l'application.

66 votes

Attention : Les variables d'environnement sont définies pour toutes les configurations de construction, elles ne peuvent pas être définies pour des configurations individuelles. Ainsi, ceci est no une solution viable si vous avez besoin que le comportement change selon qu'il s'agit d'une version ou d'un débogage.

8 votes

@Eric D'accord, mais ils ne sont pas définis pour toutes les actions du régime. Ainsi, vous pourriez faire une chose sur le build-and-run et une chose différente sur l'archive, ce qui est souvent la distinction réelle que vous voulez faire. Ou vous pouvez avoir plusieurs schémas, ce qui est également un modèle commun dans la vie réelle. De plus, comme je l'ai dit dans ma réponse, activer et désactiver les variables d'environnement dans un schéma est facile.

175voto

DShah Points 5217

Un changement majeur de ifdef de remplacement est apparu avec Xcode 8, c'est-à-dire l'utilisation de Conditions de compilation active .

Se référer à Construction et liens en Note de mise à jour de Xcode 8 .

Nouveaux paramètres de construction

Nouveau cadre : 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 n'oubliant pas de faire précéder le paramètre de "-D". Par exemple, pour compiler conditionnellement 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 devons seulement passer la valeur MYFLAG au nouveau paramètre. Il est temps de déplacer toutes ces valeurs de compilation conditionnelle !

Veuillez vous référer au lien ci-dessous pour plus de détails sur la fonctionnalité Swift Build Settings dans Xcode 8 : http://www.miqu.me/blog/2016/07/31/xcode-8-new-build-settings-and-analyzer-improvements/

96voto

KennyTM Points 232647

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

  • _isDebugAssertConfiguration() (vrai lorsque l'optimisation est définie sur -Onone )
  • _isReleaseAssertConfiguration() (vrai lorsque l'optimisation est définie sur -O ) (non disponible sur Swift 3+)
  • _isFastAssertConfiguration() (vrai 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 du préprocesseur,

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

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

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X