In C / C ++ / Objective-C è ansible definire una macro utilizzando i preprocessori del compilatore. Inoltre, puoi includere / escludere alcune parti di codice usando i preprocessori del compilatore.
#ifdef DEBUG // Debug-only code #endif
C’è una soluzione simile in Swift?
Si, puoi farlo.
In Swift puoi ancora utilizzare le macro del preprocessore “# if / # else / # endif” (sebbene più limitate), come per i documenti Apple . Ecco un esempio:
#if DEBUG let a = 2 #else let a = 3 #endif
Ora, però, devi impostare altrove il simbolo “DEBUG”. Impostalo nella sezione “Swift Compiler – Custom Flags”, “Other Swift Flags”. Si aggiunge il simbolo DEBUG con la voce -D DEBUG
.
Come al solito, puoi impostare un valore diverso in Debug o in Release.
L’ho provato in codice reale e funziona; tuttavia non sembra essere riconosciuto in un parco giochi.
Puoi leggere il mio post originale qui .
NOTA IMPORTANTE: -DDEBUG=1
non funziona. Solo -D DEBUG
funziona. Sembra che il compilatore stia ignorando una bandiera con un valore specifico.
Come dichiarato in Apple Docs
Il compilatore Swift non include un preprocessore. Al contrario, sfrutta gli attributi in fase di compilazione, le configurazioni di build e le funzionalità del linguaggio per ottenere la stessa funzionalità. Per questo motivo, le direttive del preprocessore non vengono importate in Swift.
Sono riuscito a ottenere ciò che volevo usando le Configurazioni di Build personalizzate:
Ecco come controlli la destinazione:
#if BANANA print("We have a banana") #elseif MELONA print("Melona") #else print("Kiwi") #endif
Testato usando Swift 2.2
In molte situazioni, non hai davvero bisogno di compilazione condizionale; hai solo bisogno di un comportamento condizionale che puoi triggersre e distriggersre. Per questo, è ansible utilizzare una variabile di ambiente. Questo ha l’enorme vantaggio che in realtà non è necessario ricompilare.
È ansible impostare la variabile di ambiente e triggersrla o distriggersrla facilmente nell’editor di schemi:
È ansible recuperare la variabile di ambiente con NSProcessInfo:
let dic = NSProcessInfo.processInfo().environment if dic["TRIPLE"] != nil { // ... do secret stuff here ... }
Ecco un esempio di vita reale. La mia app funziona solo sul dispositivo, perché utilizza la libreria musicale, che non esiste sul simulatore. Come, quindi, prendere schermate sul simulatore per dispositivi che non possiedo? Senza quelle schermate, non posso inviare all’AppStore.
Ho bisogno di dati falsi e un modo diverso di elaborarli . Ho due variabili di ambiente: una che, una volta accesa, dice all’app di generare i dati falsi dai dati reali mentre è in esecuzione sul mio dispositivo; l’altro che, quando acceso, utilizza i dati falsi (non la libreria musicale mancante) mentre è in esecuzione sul simulatore. Attivare / distriggersre ciascuna di queste modalità speciali è facile grazie alle caselle di controllo della variabile di ambiente nell’editor Scheme. E il vantaggio è che non posso usarli accidentalmente nella build del mio App Store, perché l’archiviazione non ha variabili d’ambiente.
Un importante cambiamento ifdef
sostituzione di ifdef
arrivato con Xcode 8. cioè l’uso delle condizioni di compilazione triggers .
Fare riferimento a Building and Linking in Xcode 8 Release note .
Nuove impostazioni di build
Nuova impostazione: SWIFT_ACTIVE_COMPILATION_CONDITIONS
“Active Compilation Conditions” is a new build setting for passing conditional compilation flags to the Swift compiler.
In precedenza, dovevamo dichiarare i flag di compilazione condizionale sotto OTHER_SWIFT_FLAGS, ricordando di anteporre “-D” all’impostazione. Ad esempio, per compilare in modo condizionale con un valore MYFLAG:
#if MYFLAG1 // stuff 1 #elseif MYFLAG2 // stuff 2 #else // stuff 3 #endif
Il valore da aggiungere all’impostazione -DMYFLAG
Ora abbiamo solo bisogno di passare il valore MYFLAG alla nuova impostazione. È ora di spostare tutti quei valori di compilazione condizionale!
Si prega di fare riferimento al link sottostante per ulteriori funzionalità di Swift Build Settings in Xcode 8: http://www.miqu.me/blog/2016/07/31/xcode-8-new-build-settings-and-analyzer-improvements/
A partire da Swift 4.1, se tutto ciò che serve è solo verificare se il codice è stato creato con la configurazione di debug o release, è ansible utilizzare le funzioni integrate:
_isDebugAssertConfiguration()
(true quando l’ottimizzazione è impostata su -Onone
) _isReleaseAssertConfiguration()
(true quando l’ottimizzazione è impostata su -O
) _isFastAssertConfiguration()
(true quando l’ottimizzazione è impostata su -Ounchecked
) per esempio
func obtain() -> AbstractThing { if _isDebugAssertConfiguration() { return DecoratedThingWithDebugInformation(Thing()) } else { return Thing() } }
Rispetto alle macro del preprocessore,
-D DEBUG
personalizzato per utilizzarlo ✗ Non documentato, il che significa che la funzione può essere rimossa in qualsiasi aggiornamento (ma dovrebbe essere protetta da AppStore poiché l’ottimizzatore le trasformsrà in costanti)
@testable
, il destino è incerto sul futuro Swift. ✗ Usando in se / else genererà sempre un avviso “Non verrà mai eseguito”.
Utilizza l’impostazione Condizioni di compilazione triggers in Impostazioni di compilazione / Compilatore Swift – Bandiere personalizzate .
ALPHA
, BETA
ecc. Quindi controllalo con condizioni di compilazione come questa:
#if ALPHA // #elseif BETA // #else // #endif
Suggerimento: puoi anche usare
#if !ALPHA
ecc.
Non esiste un preprocessore Swift. (Per prima cosa, la sostituzione arbitraria del codice interrompe la sicurezza del tipo e della memoria.)
Swift include anche opzioni di configurazione in fase di costruzione, quindi puoi includere in modo condizionale codice per determinate piattaforms o stili di compilazione o in risposta a flag definiti con argomenti del compilatore -D
. A differenza di C, tuttavia, una sezione compilata in modo condizionale del codice deve essere sintatticamente completa. C’è una sezione su questo in Uso di Swift con Cocoa e Objective-C .
Per esempio:
#if os(iOS) let color = UIColor.redColor() #else let color = NSColor.redColor() #endif
I miei due centesimi per Xcode 8:
a) Una bandiera personalizzata che usa il prefisso -D
funziona bene, ma …
b) Uso più semplice:
In Xcode 8 c’è una nuova sezione: “Condizioni di compilazione triggers”, già con due righe, per il debug e il rilascio.
Aggiungi semplicemente il tuo define WITHOUT -D
.
Un’altra soluzione, forse più semplice, che risulta ancora in un booleano che è ansible passare in funzioni senza #if
condizionamento #if
tutta la base di codice è definire DEBUG
come una delle Active Compilation Conditions
del target di Active Compilation Conditions
e includere quanto segue (lo definisco come costante globale):
#if DEBUG let isDebug = true #else let isDebug = false #endif
Questo concetto si basa sulla risposta di Kennytm
Il vantaggio principale quando si confronta con kennytm, è che questo non si basa su metodi privati o non documentati.
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 }()
Rispetto alle macro del preprocessore e alla risposta di kennytm ,
-D DEBUG
personalizzato per utilizzarlo ✓ Documentato , il che significa che la funzione seguirà i normali schemi di rilascio / deprivazione dell’API.
✓ L’uso di in if / else non genererà un avviso “Non verrà mai eseguito”.
Dopo aver impostato DEBUG=1
nelle tue GCC_PREPROCESSOR_DEFINITIONS
Build Settings, preferisco usare una funzione per effettuare queste chiamate:
func executeInProduction(_ block: () -> Void) { #if !DEBUG block() #endif }
E quindi semplicemente racchiudere in questa funzione qualsiasi blocco che voglio omesso nei build di Debug:
executeInProduction { Fabric.with([Crashlytics.self]) // Compiler checks this line even in Debug }
Il vantaggio rispetto a:
#if !DEBUG Fabric.with([Crashlytics.self]) // This is not checked, may not compile in non-Debug builds #endif
È che il compilatore controlla la syntax del mio codice, quindi sono sicuro che la sua syntax è corretta e costruisce.
Questo si basa sulla risposta di Jon Willis che si basa sull’asserzione, che viene eseguita solo nelle compilation di Debug:
func Log(_ str: String) { assert(DebugLog(str)) } func DebugLog(_ str: String) -> Bool { print(str) return true }
Il mio caso d’uso è per la registrazione delle dichiarazioni di stampa. Ecco un punto di riferimento per la versione di rilascio su 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)" )
stampe:
Log: 0.0
Sembra che Swift 4 elimina completamente la chiamata di funzione.
! [In Xcode 8 e sopra vai a build impostazioni -> cerca bandiere personalizzate] 1
Nel codice
#if Live print("Live") #else print("debug") #endif