In C/C++/Objective-C können Sie mithilfe von Compiler-Präprozessoren ein Makro definieren. Darüber hinaus können Sie mithilfe von Compiler-Präprozessoren einige Teile des Codes ein- oder ausschließen.
#ifdef DEBUG
// Debug-only code
#endif
Gibt es eine ähnliche Lösung in Swift?
Ja, du kannst es schaffen.
In Swift können Sie weiterhin die Präprozessor-Makros "# if/# else/# endif" verwenden (obwohl eingeschränkter), wie in Apple docs angegeben. Hier ist ein Beispiel:
#if DEBUG
let a = 2
#else
let a = 3
#endif
Jetzt müssen Sie jedoch das "DEBUG" -Symbol an einer anderen Stelle setzen. Stellen Sie es im Abschnitt "Swift Compiler - Custom Flags" in der Zeile "Other Swift Flags" ein. Sie fügen das DEBUG-Symbol mit dem Eintrag -D DEBUG
hinzu.
Wie üblich können Sie im Debug- oder Release-Modus 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 lesen hier .
WICHTIGER HINWEIS: -DDEBUG=1
funktioniert nicht. Nur -D DEBUG
funktioniert. Der Compiler scheint ein Flag mit einem bestimmten Wert zu ignorieren.
Wie in Apple Docs angegeben
Der Compiler Swift enthält keinen Präprozessor. Stattdessen werden Attribute zur Kompilierungszeit, Buildkonfigurationen und Sprachfunktionen verwendet, um die gleiche Funktionalität zu erzielen. Aus diesem Grund werden Präprozessor-Direktiven nicht in Swift importiert.
Ich habe es geschafft, mit benutzerdefinierten Build-Konfigurationen das zu erreichen, was ich wollte:
So überprüfen Sie das Ziel:
#if BANANA
print("We have a banana")
#elseif MELONA
print("Melona")
#else
print("Kiwi")
#endif
Getestet mit Swift 2.2
In vielen Situationen brauchen Sie nicht wirklich bedingte Kompilierung; Sie brauchen nur bedingte Verhalten, dass 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 ganz einfach ein- oder ausschalten:
Sie können die Umgebungsvariable mit NSProcessInfo abrufen:
let dic = NSProcessInfo.processInfo().environment
if dic["TRIPLE"] != nil {
// ... do secret stuff here ...
}
Hier ist ein reales Beispiel. Meine App wird nur auf dem Gerät ausgeführt, 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 mich nicht beim AppStore anmelden.
Ich brauche gefälschte Daten und andere Art der Verarbeitung. 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 werden; Die andere verwendet beim Einschalten die gefälschten Daten (nicht die fehlende Musikbibliothek), während sie auf dem Simulator ausgeführt wird. Das Ein- und Ausschalten dieser speziellen Modi ist dank der Kontrollkästchen für Umgebungsvariablen im Schema-Editor ganz einfach. Und der Bonus ist, dass ich sie nicht versehentlich in meinem App Store Build verwenden kann, da die Archivierung keine Umgebungsvariablen enthält.
Eine wesentliche Änderung des ifdef
-Ersatzes ergab sich mit Xcode 8. d. H. Verwendung von Active Compilation Conditions .
Siehe Erstellen und Verknüpfen in Xcode 8-Versionshinweis .
Neue Build-Einstellungen
Neue Einstellung: Swift_ACTIVE_COMPILATION_CONDITIONS
“Active Compilation Conditions” is a new build setting for passing conditional compilation flags to the Swift compiler.
Zuvor mussten wir Ihre bedingten Kompilierungsflags unter OTHER_Swift_FLAGS deklarieren und daran denken, der Einstellung "-D" voranzustellen. So kompilieren Sie beispielsweise bedingt mit einem MYFLAG-Wert:
#if MYFLAG1
// stuff 1
#elseif MYFLAG2
// stuff 2
#else
// stuff 3
#endif
Der Wert, der zur Einstellung -DMYFLAG
hinzugefügt werden soll
Jetzt müssen wir nur noch den Wert MYFLAG an die neue Einstellung übergeben. Es ist Zeit, alle diese bedingten Kompilierungswerte zu verschieben!
Weitere Swift Build-Einstellungen in Xcode 8 finden Sie unter folgendem Link: http://www.miqu.me/blog/2016/07/31/xcode-8-new- Build-Einstellungen-und-Analyzer-Verbesserungen/
Ab Swift 4.1 können Sie die integrierten Funktionen verwenden, wenn Sie nur überprüfen müssen, ob der Code mit Debug- oder Release-Konfiguration erstellt wurde:
_isDebugAssertConfiguration()
(true, wenn die Optimierung auf -Onone
eingestellt ist)_isReleaseAssertConfiguration()
(true, wenn die Optimierung auf -O
gesetzt ist)_isFastAssertConfiguration()
(true, wenn die Optimierung auf -Ounchecked
gesetzt ist)z.B.
func obtain() -> AbstractThing {
if _isDebugAssertConfiguration() {
return DecoratedThingWithDebugInformation(Thing())
} else {
return Thing()
}
}
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 der Optimierer diese in Konstanten umwandelt).
@testable
fehlt , das Schicksal des zukünftigen Swift ungewiss.✗ Wenn Sie in if/else verwenden, wird immer die Warnung "Wird nie ausgeführt" ausgegeben.
Verwenden Sie die Einstellung Active Compilation Conditions in Build settings/Swift Compiler - Benutzerdefinierte Flags .
ALPHA
, BETA
usw.Dann überprüfe es mit Kompilierungsbedingungen wie folgt:
#if ALPHA
//
#elseif BETA
//
#else
//
#endif
Tipp: Sie können auch
#if !ALPHA
usw.
Es gibt keinen Swift Präprozessor. (Zum einen unterbricht die Ersetzung willkürlichen Codes die Typ- und Speichersicherheit.)
Swift enthält jedoch Konfigurationsoptionen für die Erstellungszeit, sodass Sie Code für bestimmte Plattformen oder Erstellungsstile oder als Reaktion auf Flags, die Sie mit den Compiler-Argumenten -D
definieren, unter bestimmten Bedingungen einbinden 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 mit Cocoa und Objective-C .
Zum Beispiel:
#if os(iOS)
let color = UIColor.redColor()
#else
let color = NSColor.redColor()
#endif
Meine zwei Cent für Xcode 8:
a) Ein benutzerdefiniertes Flag mit dem Präfix -D
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 WITHOUT -D
hinzu.
Eine andere, vielleicht einfachere Lösung, die immer noch zu einem Booleschen Wert führt, den Sie an Funktionen übergeben können, ohne die Bedingungen für #if
in Ihrer Codebasis zu ändern, besteht darin, DEBUG
als einen der Werte für Active Compilation Conditions
und Ihres Projektbuild-Ziels zu definieren füge folgendes hinzu (ich definiere es als globale Konstante):
#if DEBUG
let isDebug = true
#else
let isDebug = false
#endif
Dieses Konzept baut auf kennytms Antwort auf
Der Hauptvorteil beim Vergleich mit Kennytmen ist, dass dies nicht auf privaten oder undokumentierten Methoden beruht.
In 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
}()
Im Vergleich zu Präprozessor-Makros und der Antwort von kennytm
-D DEBUG
-Flag definieren, um es zu verwenden✓ Dokumentiert , dh die Funktion folgt den normalen API-Release-/Verfallsmustern.
✓ Wenn Sie in if/else nicht verwenden, wird die Warnung "Wird nie ausgeführt" ausgegeben.
In Swift Projekten, die mit Xcode Version 9.4.1 erstellt wurden, Swift 4.1
#if DEBUG
#endif
funktioniert standardmäßig, da in den Präprozessor-Makros DEBUG = 1 bereits von Xcode gesetzt wurde.
Sie können also #if DEBUG "out of box" verwenden.
Übrigens, wie man die Bedingungskompilierungsblöcke im Allgemeinen verwendet, steht in Apples Buch The Swift Programming Language 4.1 (Abschnitt Compiler Control Statements) und wie man die Kompilierungsflags schreibt und was das Gegenstück zu C ist Makros in Swift sind in einem anderen Apple-Buch geschrieben. Verwenden von Swift mit Cocoa und Objective C (im Abschnitt Präprozessor-Direktiven)
Hoffe in Zukunft Apple wird die detaillierteren Inhalte und die Indizes für ihre Bücher schreiben.
XCODE 9 UND OBEN
#if DEVELOP
//
#elseif PRODCTN
//
#else
//
#endif
Nachdem Sie DEBUG=1
in Ihrem GCC_PREPROCESSOR_DEFINITIONS
Build-Einstellungen festgelegt haben, bevorzuge ich die Verwendung einer Funktion für diese Aufrufe:
func executeInProduction(_ block: () -> Void)
{
#if !DEBUG
block()
#endif
}
Und schließen Sie dann in diese Funktion einfach jeden Block ein, den ich in Debug-Builds weglassen möchte:
executeInProduction {
Fabric.with([Crashlytics.self]) // Compiler checks this line even in Debug
}
Der Vorteil gegenüber:
#if !DEBUG
Fabric.with([Crashlytics.self]) // This is not checked, may not compile in non-Debug builds
#endif
Ist das der Compiler die Syntax meines Codes überprüft, so bin ich sicher, dass seine Syntax korrekt ist und baut.
Moignans Antwort hier funktioniert gut. Hier ist eine weitere Info, falls es hilft,
#if DEBUG
let a = 2
#else
let a = 3
#endif
Sie können die Makros wie folgt negieren,
#if !RELEASE
let a = 2
#else
let a = 3
#endif
! [In Xcode 8 und höher gehen Sie zur Build-Einstellung -> Suche nach benutzerdefinierten Flags]1
In Code
#if Live
print("Live")
#else
print("debug")
#endif
Dies baut auf Jon Willis einer Antwort auf, die auf assert beruht und nur in Debug-Kompilierungen ausgeführt wird:
func Log(_ str: String) {
assert(DebugLog(str))
}
func DebugLog(_ str: String) -> Bool {
print(str)
return true
}
Mein Anwendungsfall ist die Protokollierung von Druckanweisungen. Hier ist ein Benchmark für die Release-Version auf dem iPhone X:
let iterations = 100_000_000
let time1 = CFAbsoluteTimeGetCurrent()
for i in 0 ..< iterations {
Log ("⧉ unarchiveArray:\(fileName) memoryTime:\(memoryTime) count:\(array.count)")
}
var time2 = CFAbsoluteTimeGetCurrent()
print ("Log: \(time2-time1)" )
druckt:
Log: 0.0
Sieht aus wie Swift 4 den Funktionsaufruf vollständig beseitigt.
func inDebugBuilds(_ code: () -> Void) {
assert({ code(); return true }())
}