In C / C ++ / Objective C können Sie ein Makro mithilfe von Compiler-Präprozessoren definieren. Darüber hinaus können Sie einige Codeteile mithilfe von Compiler-Präprozessoren ein- / ausschließen.
#ifdef DEBUG
// Debug-only code
#endif
Gibt es eine ähnliche Lösung in Swift?
Antworten:
Ja, du kannst es schaffen.
In Swift können Sie weiterhin die Präprozessor-Makros "# if / # else / # endif" (obwohl eingeschränkter) gemäß Apple-Dokumenten verwenden . Hier ist ein Beispiel:
Jetzt müssen Sie das Symbol "DEBUG" jedoch an einer anderen Stelle setzen. Stellen Sie es im Abschnitt "Swift Compiler - Benutzerdefinierte Flags" in der Zeile "Andere Swift Flags" ein. Sie fügen dem
-D DEBUG
Eintrag das DEBUG-Symbol hinzu .Wie üblich können Sie im Debug oder im Release einen anderen Wert festlegen.
Ich habe es in echtem Code getestet und es funktioniert; es scheint jedoch auf einem Spielplatz nicht erkannt zu werden.
Sie können meinen ursprünglichen Beitrag hier lesen .
WICHTIGER HINWEIS:
-DDEBUG=1
funktioniert nicht. Funktioniert nur-D DEBUG
. Der Compiler ignoriert anscheinend ein Flag mit einem bestimmten Wert.quelle
-D DEBUG
wie oben angegeben müssen Sie auchDEBUG=1
inApple LLVM 6.0 - Preprocessing
-> definierenPreprocessor Macros
.-DDEBUG
von dieser Antwort in geändert habe : stackoverflow.com/a/24112024/747369 .DEBUG=1
zuPreprocessor Macros
, wenn Sie es im Code Objective-C nicht verwendet werden sollen.Wie in Apple Docs angegeben
Ich habe es geschafft, mit benutzerdefinierten Build-Konfigurationen das zu erreichen, was ich wollte:
So überprüfen Sie das Ziel:
Getestet mit Swift 2.2
quelle
-DLOCAL
auf meinem gesetzt habe#if LOCAl #else #endif
, fällt es in den#else
Abschnitt. Ich habe das ursprüngliche Ziel dupliziertAppTarget
und es umbenanntAppTargetLocal
und das benutzerdefinierte Flag gesetzt.#if LOCAL
das beabsichtigte Ergebnis fällt , wenn ich mit dem Simulator laufe und#else
beim Testen hineinfällt. Ich möchte, dass es#if LOCAL
auch beim Testen hineinfällt.In vielen Situationen benötigen Sie keine bedingte Kompilierung . Sie brauchen nur bedingtes Verhalten , das Sie ein- und ausschalten können. Dafür können Sie eine Umgebungsvariable verwenden. Dies hat den großen Vorteil, dass Sie nicht neu kompilieren müssen.
Sie können die Umgebungsvariable im Schema-Editor festlegen und einfach ein- oder ausschalten:
Sie können die Umgebungsvariable mit NSProcessInfo abrufen:
Hier ist ein Beispiel aus dem wirklichen Leben. Meine App läuft nur auf dem Gerät, da sie die Musikbibliothek verwendet, die im Simulator nicht vorhanden ist. Wie mache ich dann Screenshots im Simulator für Geräte, die ich nicht besitze? Ohne diese Screenshots kann ich nicht an den AppStore senden.
Ich brauche gefälschte Daten und eine andere Art, sie zu verarbeiten . Ich habe zwei Umgebungsvariablen: eine, die die App beim Einschalten anweist, die gefälschten Daten aus den realen Daten zu generieren, während sie auf meinem Gerät ausgeführt wird; die andere, die beim Einschalten die gefälschten Daten (nicht die fehlende Musikbibliothek) verwendet, während sie auf dem Simulator ausgeführt wird. Das Ein- und Ausschalten jedes dieser speziellen Modi ist dank der Kontrollkästchen für Umgebungsvariablen im Schema-Editor einfach. Und der Bonus ist, dass ich sie nicht versehentlich in meinem App Store-Build verwenden kann, da die Archivierung keine Umgebungsvariablen enthält.
quelle
ifdef
Mit Xcode 8 wurde eine wesentliche Änderung des Ersatzes vorgenommen, dh die Verwendung der Bedingungen für die aktive Kompilierung .Siehe Erstellen und Verknüpfen in Xcode 8 Versionshinweis .
Neue Build-Einstellungen
Neue Einstellung:
SWIFT_ACTIVE_COMPILATION_CONDITIONS
Zuvor mussten wir Ihre bedingten Kompilierungsflags unter OTHER_SWIFT_FLAGS deklarieren und dabei daran denken, der Einstellung "-D" voranzustellen. Zum bedingten Kompilieren mit einem MYFLAG-Wert:
Der Wert, der der Einstellung hinzugefügt werden soll
-DMYFLAG
Jetzt müssen wir nur noch den Wert MYFLAG an die neue Einstellung übergeben. Zeit, all diese bedingten Kompilierungswerte zu verschieben!
Weitere Funktionen für schnelle Build-Einstellungen in Xcode 8 finden Sie unter dem folgenden Link: http://www.miqu.me/blog/2016/07/31/xcode-8-new-build-settings-and-analyzer-improvements/
quelle
Ab Swift 4.1 können Sie die integrierten Funktionen verwenden, wenn Sie nur prüfen müssen, ob der Code mit Debug- oder Release-Konfiguration erstellt wurde:
_isDebugAssertConfiguration()
(wahr, wenn die Optimierung auf eingestellt ist-Onone
)(nicht verfügbar bei Swift 3+)_isReleaseAssertConfiguration()
(wahr, wenn die Optimierung auf eingestellt ist-O
)_isFastAssertConfiguration()
(wahr, wenn die Optimierung auf eingestellt ist-Ounchecked
)z.B
Im Vergleich zu Präprozessor-Makros
-D DEBUG
Flag definieren , um es zu verwenden✗ Undokumentiert, was bedeutet, dass die Funktion bei jedem Update entfernt werden kann (sie sollte jedoch AppStore-sicher sein, da das Optimierungsprogramm diese in Konstanten umwandelt).
@testable
Attribute wieder an die Öffentlichkeit gebracht. Das Schicksal ist für den zukünftigen Swift ungewiss.✗ Wenn Sie in if / else verwenden, wird immer die Warnung "Wird nie ausgeführt" generiert.
quelle
if _isDebugAssertConfiguration()
wirdif false
im Release-Modus ausgewertet undif true
ist im Debug-Modus.Xcode 8 und höher
Verwenden Sie die Einstellung Active Compilation Conditions unter Build Settings / Swift Compiler - Custom Flags .
ALPHA
,BETA
usw.Überprüfen Sie es dann mit folgenden Kompilierungsbedingungen :
quelle
Es gibt keinen Swift-Präprozessor. (Zum einen beeinträchtigt die willkürliche Codesubstitution die Typ- und Speichersicherheit.)
Swift enthält jedoch Konfigurationsoptionen für die Build-Zeit, sodass Sie Code für bestimmte Plattformen oder Build-Stile oder als Reaktion auf Flags, die Sie mit
-D
Compiler-Argumenten definieren, bedingt einschließen können . Im Gegensatz zu C muss ein bedingt kompilierter Abschnitt Ihres Codes jedoch syntaktisch vollständig sein. Es gibt einen Abschnitt darüber in Verwenden von Swift With Cocoa und Objective-C .Zum Beispiel:
quelle
INT_CONST
überall dort platzieren könnenfloat
, wo sie akzeptiert werden. Swift würde das nicht zulassen. Wenn Sie diesvar floatVal = INT_CONST
zwangsläufig tun könnten , würde es irgendwann später zusammenbrechen, wenn der Compiler eine erwartetInt
, Sie sie jedoch alsFloat
(Typ von wirdfloatVal
als abgeleitetInt
) verwenden. 10 Würfe später und es ist nur sauberer, um Makros zu entfernen ...Meine zwei Cent für Xcode 8:
a) Ein benutzerdefiniertes Flag mit dem
-D
Präfix funktioniert einwandfrei, aber ...b) Einfachere Verwendung:
In Xcode 8 gibt es einen neuen Abschnitt: "Active Compilation Conditions", bereits mit zwei Zeilen, zum Debuggen und Freigeben.
Fügen Sie einfach Ihre Definition OHNE hinzu
-D
.quelle
-D
.isDebug-Konstante basierend auf aktiven Kompilierungsbedingungen
Eine andere, vielleicht einfachere Lösung, die immer noch zu einem Booleschen Wert führt, den Sie an Funktionen übergeben können, ohne die
#if
Bedingungen in Ihrer Codebasis zu verbessern , besteht darin,DEBUG
als eines Ihrer Projekterstellungsziele zu definierenActive Compilation Conditions
und Folgendes einzuschließen (ich definiere es als globale Konstante):isDebug-Konstante basierend auf den Einstellungen für die Compileroptimierung
Dieses Konzept baut auf der Antwort von kennytm auf
Der Hauptvorteil beim Vergleich mit Kennytms besteht darin, dass dies nicht auf privaten oder nicht dokumentierten Methoden beruht.
In Swift 4 :
Im Vergleich mit Präprozessormakros und Antwort des kennytm ,
-D DEBUG
Flag definieren , um es zu verwenden✓ Dokumentiert , was bedeutet, dass die Funktion normalen API-Freigabe- / Verfallsmustern folgt.
✓ Wenn Sie in if / else verwenden, wird keine Warnung "Wird niemals ausgeführt" generiert.
quelle
Moignans Antwort hier funktioniert gut. Hier ist eine weitere Information, falls es hilft,
Sie können die Makros wie folgt negieren.
quelle
In Swift-Projekten, die mit Xcode Version 9.4.1 erstellt wurden, ist Swift 4.1
funktioniert standardmäßig, da in den Präprozessor-Makros DEBUG = 1 bereits von Xcode festgelegt wurde.
Sie können also #if DEBUG "out of box" verwenden.
Übrigens ist in Apples Buch The Swift Programming Language 4.1 (Abschnitt Compiler Control Statements) beschrieben, wie die Bedingungskompilierungsblöcke im Allgemeinen verwendet werden und wie die Kompilierungsflags geschrieben werden und was das Gegenstück zu den C-Makros in Swift ist ein anderes Apple-Buch Verwenden von Swift mit Kakao und Ziel C (im Abschnitt Präprozessor-Richtlinien)
Wir hoffen, dass Apple in Zukunft die detaillierteren Inhalte und die Indizes für ihre Bücher schreiben wird.
quelle
XCODE 9 UND OBEN
quelle
Nach dem Festlegen
DEBUG=1
IhrerGCC_PREPROCESSOR_DEFINITIONS
Build-Einstellungen bevorzuge ich die Verwendung einer Funktion, um diese Aufrufe zu tätigen:Und dann fügen Sie in diese Funktion einfach jeden Block ein, den ich in Debug-Builds weglassen möchte:
Der Vorteil gegenüber:
Ist das, dass der Compiler die Syntax meines Codes überprüft, so bin ich sicher, dass seine Syntax korrekt ist und erstellt.
quelle
! [In Xcode 8 und höher gehen Sie zu Build-Einstellung -> Suche nach benutzerdefinierten Flags] 1
In Code
quelle
Quelle
quelle
@inlinable
vorfunc
und dies wäre der eleganteste und idiomatischste Weg für Swift. In Release-Builds wird Ihrcode()
Block optimiert und vollständig entfernt. Eine ähnliche Funktion wird in Apples eigenem NIO-Framework verwendet.Dies baut auf Jon Willis ' Antwort auf, die auf Assert beruht und nur in Debug-Kompilierungen ausgeführt wird:
Mein Anwendungsfall ist das Protokollieren von Druckanweisungen. Hier ist ein Benchmark für die Release-Version auf dem iPhone X:
Drucke:
Es sieht so aus, als würde Swift 4 den Funktionsaufruf vollständig eliminieren.
quelle