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.

91voto

Jakub Truhlář Points 7104

Xcode 8 et plus

Utilisez Conditions de compilation active à l'intérieur Paramètres de construction / Compilateur Swift - Drapeaux personnalisés .

  • Il s'agit du nouveau paramètre de construction permettant de transmettre des indicateurs de compilation conditionnelle au compilateur Swift.
  • Ajoutez simplement des drapeaux comme ceci : ALPHA , BETA etc.

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

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

Conseil : vous pouvez également utiliser #if !ALPHA etc.

80voto

rickster Points 19870

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

Swift comprend toutefois des options de configuration au moment de la construction, de sorte que vous pouvez inclure du code de manière conditionnelle pour certaines plateformes ou certains styles de construction, ou en réponse à des drapeaux que vous définissez à l'aide de la commande -D les arguments du compilateur. Contrairement au C, cependant, une section de votre code compilé conditionnellement doit être syntaxiquement complète. Il y a une section à ce sujet dans Utiliser Swift avec Cocoa et Objective-C .

Par exemple :

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

38 votes

"D'une part, la substitution arbitraire de code brise la sécurité de type et de mémoire." Un pré-processeur ne fait-il pas son travail avant le compilateur (d'où son nom) ? Donc toutes ces vérifications peuvent encore avoir lieu.

10 votes

Thilo, je pense que ce qui est cassé est le support IDE.

1 votes

Je pense que ce que @rickster veut dire, c'est que les macros du préprocesseur C ne comprennent pas les types et que leur présence serait contraire aux exigences de Swift en matière de types. La raison pour laquelle les macros fonctionnent en C est que le C permet une conversion implicite des types, ce qui signifie que vous pourriez mettre votre code INT_CONST n'importe où un float serait accepté. Swift ne le permettrait pas. De même, si vous pouviez faire var floatVal = INT_CONST inévitablement, il se briserait quelque part plus tard quand le compilateur attend un Int mais vous l'utilisez comme un Float (type de floatVal serait déduit comme Int ). 10 castings plus tard et c'est juste plus propre pour enlever les macros...

56voto

Jon Willis Points 3271

Constante isDebug basée sur les conditions de compilation active

Une autre solution, peut-être plus simple, qui donne toujours un booléen que l'on peut passer dans les fonctions sans avoir besoin d'utiliser des poivrons #if conditionnelles dans l'ensemble de votre base de code est de définir DEBUG comme l'une des cibles de construction de votre projet Active Compilation Conditions et inclure ce qui suit (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 à la méthode de kennytm est qu'elle ne repose pas sur des méthodes privées ou non documentées.

Sur 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 du préprocesseur et la réponse de kennytm ,

  • 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.

  • Documenté ce qui signifie que la fonction suivra les schémas normaux de publication et de dépréciation des API.

  • L'utilisation de la méthode if/else no générer un avertissement "Ne sera jamais exécuté".

52voto

ingconti Points 405

Mes deux centimes pour Xcode 8 :

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

b) Une utilisation plus simple :

Dans Xcode 8, il y a une nouvelle section : "Conditions de compilation active", déjà avec deux rangées, pour debug et release.

Il suffit d'ajouter votre définition SANS -D .

40voto

Hissain Points 880

Moignans réponse ici fonctionne bien. Voici une autre information au cas où elle serait utile,

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

Vous pouvez annuler les macros comme ci-dessous,

#if !RELEASE
    let a = 2
#else
    let a = 3
#endif

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