tutorial teacher playgrounds mac for apple app swift xcode preprocessor preprocessor-directive

teacher - #ifdef reemplazo en el lenguaje Swift



swift playgrounds for mac (14)

En C / C ++ / Objective-C puede definir una macro utilizando preprocesadores del compilador. Además, puede incluir / excluir algunas partes de código usando preprocesadores de compilación.

#ifdef DEBUG // Debug-only code #endif

¿Hay una solución similar en Swift?


Xcode 8 y superior

Use la configuración Condiciones de compilación activa en Configuración de compilación / Compilador Swift - Banderas personalizadas .

  • Esta es la nueva configuración de compilación para pasar banderas de compilación condicional al compilador Swift.
  • Simplemente agregue banderas como esta: ALPHA , BETA , etc.

Luego verifíquelo con condiciones de compilación como esta:

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

Consejo: También puedes usar #if !ALPHA etc.


Constante de isDebug basada en condiciones de compilación activa

Otra solución, tal vez más simple, que aún resulta en un booleano que puede pasar a funciones sin #if condicionales #if lo largo de su base de código es definir DEBUG como una de las Active Compilation Conditions de su proyecto de destino de Active Compilation Conditions e incluir lo siguiente (lo defino como un constante global):

#if DEBUG let isDebug = true #else let isDebug = false #endif

Constante de isDebug basada en la configuración de optimización del compilador

Este concepto se basa en la respuesta de Kennytm.

La principal ventaja cuando se compara con los de kennytm, es que esto no se basa en métodos privados o indocumentados.

En 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 }()

Comparado con las macros del preprocesador y la respuesta de kennytm ,

  • ✓ No necesita definir un indicador -D DEBUG personalizado para usarlo
  • ~ En realidad se define en términos de configuración de optimización, no de configuración de compilación Xcode
  • Documentado , lo que significa que la función seguirá los patrones normales de liberación / desaprobación de la API.

  • ✓ Usar en si / else no generará una advertencia "Nunca se ejecutará".


A partir de Swift 4.1, si todo lo que necesita es simplemente verificar si el código está creado con la configuración de debug o release, puede usar las funciones integradas:

  • _isDebugAssertConfiguration() (verdadero cuando la optimización se establece en -Onone )
  • _isReleaseAssertConfiguration() (verdadero cuando la optimización se establece en -O ) (no disponible en Swift 3+)
  • _isFastAssertConfiguration() (verdadero cuando la optimización se establece en -Ounchecked )

p.ej

func obtain() -> AbstractThing { if _isDebugAssertConfiguration() { return DecoratedThingWithDebugInformation(Thing()) } else { return Thing() } }

Comparado con las macros preprocesadoras,

  • ✓ No necesita definir un indicador -D DEBUG personalizado para usarlo
  • ~ En realidad se define en términos de configuración de optimización, no de configuración de compilación Xcode
  • D Sin documentar, lo que significa que la función se puede eliminar en cualquier actualización (pero debería ser segura para AppStore, ya que el optimizador las convertirá en constantes)

  • ✗ Usar en si / else siempre generará una advertencia "Nunca se ejecutará".


Como se indica en Apple Docs

El compilador Swift no incluye un preprocesador. En su lugar, aprovecha los atributos de tiempo de compilación, las configuraciones de compilación y las características de lenguaje para lograr la misma funcionalidad. Por esta razón, las directivas de preprocesador no se importan en Swift.

Logré lograr lo que quería usando configuraciones de compilación personalizadas:

  1. Vaya a su proyecto / seleccione su destino / Configuraciones de construcción / búsqueda de banderas personalizadas
  2. Para su objetivo elegido, establezca su marca personalizada usando el prefijo -D (sin espacios en blanco), tanto para Depurar como para Liberar
  3. Haz los pasos anteriores para cada objetivo que tengas

Así es como verificas el objetivo:

#if BANANA print("We have a banana") #elseif MELONA print("Melona") #else print("Kiwi") #endif

Probado utilizando Swift 2.2


Después de configurar DEBUG=1 en su GCC_PREPROCESSOR_DEFINITIONS Configuración de configuración Prefiero usar una función para realizar estas llamadas:

func executeInProduction(_ block: () -> Void) { #if !DEBUG block() #endif }

Y luego simplemente encierre en esta función cualquier bloque que quiera omitir en las compilaciones de depuración:

executeInProduction { Fabric.with([Crashlytics.self]) // Compiler checks this line even in Debug }

La ventaja en comparación con:

#if !DEBUG Fabric.with([Crashlytics.self]) // This is not checked, may not compile in non-Debug builds #endif

Es que el compilador comprueba la sintaxis de mi código, por lo que estoy seguro de que su sintaxis es correcta y compila.


En muchas situaciones, realmente no necesita compilación condicional; solo necesitas un comportamiento condicional que puedas activar y desactivar. Para eso, puedes usar una variable de entorno. Esto tiene la gran ventaja de que realmente no tienes que recompilar.

Puede establecer la variable de entorno y activarla o desactivarla fácilmente en el editor de esquemas:

Puede recuperar la variable de entorno con NSProcessInfo:

let dic = NSProcessInfo.processInfo().environment if dic["TRIPLE"] != nil { // ... do secret stuff here ... }

Aquí hay un ejemplo de la vida real. Mi aplicación solo se ejecuta en el dispositivo, ya que utiliza la biblioteca de música, que no existe en el simulador. ¿Cómo, entonces, tomar capturas de pantalla en el simulador para dispositivos que no tengo? Sin esas capturas de pantalla, no puedo enviarlas a la AppStore.

Necesito datos falsos y una forma diferente de procesarlos . Tengo dos variables de entorno: una que, cuando está encendida, le dice a la aplicación que genere los datos falsos de los datos reales mientras se ejecuta en mi dispositivo; el otro que, cuando está encendido, utiliza los datos falsos (no la biblioteca de música que falta) mientras se ejecuta en el simulador. Activar / desactivar cada uno de esos modos especiales es fácil gracias a las casillas de verificación de variables de entorno en el editor de Esquemas. Y la ventaja es que no puedo usarlos accidentalmente en la compilación de mi App Store, porque el archivo no tiene variables de entorno.


En proyectos Swift creados con Xcode Versión 9.4.1, Swift 4.1

#if DEBUG #endif

funciona de forma predeterminada porque en las macros del preprocesador DEBUG = 1 ya ha sido configurado por Xcode.

Así que puedes usar #if DEBUG "out of box".

Por cierto, la forma de usar los bloques de compilación de condiciones en general está escrita en el libro de Apple The Swift Programming Language 4.1 (la sección Declaraciones de control del compilador) y cómo escribir las banderas de compilación y lo que es equivalente de las macros C en Swift está escrito otro libro de Apple Utilizando Swift con Cocoa y Objective C (en la sección Directivas de preprocesador)

Esperanza en el futuro Apple escribirá los contenidos más detallados y los índices de sus libros.


Esto se basa en la respuesta de Jon Willis que se basa en asertar, que solo se ejecuta en las compilaciones de depuración:

func Log(_ str: String) { assert(DebugLog(str)) } func DebugLog(_ str: String) -> Bool { print(str) return true }

Mi caso de uso es para el registro de declaraciones impresas. Aquí hay un punto de referencia para la versión de lanzamiento en 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)" )

huellas dactilares:

Log: 0.0

Parece que Swift 4 elimina completamente la llamada de función.


Mis dos centavos para Xcode 8:

a) Un indicador personalizado que usa el prefijo -D funciona bien, pero ...

b) Uso más sencillo:

En Xcode 8 hay una nueva sección: "Condiciones de compilación activas", ya con dos filas, para depuración y lanzamiento.

Simplemente añada su define SIN -D .


No hay preprocesador Swift. (Por un lado, la sustitución de código arbitrario rompe la seguridad de tipo y de memoria).

Sin embargo, Swift incluye opciones de configuración en tiempo de compilación, por lo que puede incluir condicionalmente el código para ciertas plataformas o estilos de compilación o en respuesta a los indicadores que define con -D compiler args. Sin embargo, a diferencia de C, una sección compilada condicionalmente de su código debe estar completa sintácticamente. Hay una sección sobre esto en Uso de Swift con Cocoa y Objective-C .

Por ejemplo:

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


Sí, tú puedes hacerlo.

En Swift, todavía puedes usar las macros del preprocesador "# if / # else / # endif" (aunque más restringidas), según los documentos de Apple . Aquí hay un ejemplo:

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

Sin embargo, ahora debes configurar el símbolo "DEBUG" en otra parte. Colóquelo en la sección "Compilador de Swift - Banderas personalizadas", línea "Otros indicadores de Swift". Usted agrega el símbolo DEBUG con la entrada -D DEBUG .

Como de costumbre, puede establecer un valor diferente cuando esté en la depuración o cuando esté en la versión.

Lo probé en código real y funciona; Aunque no parece ser reconocido en un patio de recreo.

Puedes leer mi post original here .

NOTA IMPORTANTE: -DDEBUG=1 no funciona. Solo funciona la -D DEBUG . Parece que el compilador está ignorando una bandera con un valor específico.


Un cambio importante en el reemplazo de ifdef ocurrió con Xcode 8. es decir, el uso de las Condiciones de compilación activas .

Consulte Crear y enlazar en Xcode 8 Release note .

Nuevas configuraciones de construcción

Nueva configuración: SWIFT_ACTIVE_COMPILATION_CONDITIONS

“Active Compilation Conditions” is a new build setting for passing conditional compilation flags to the Swift compiler.

Anteriormente, teníamos que declarar tus banderas de compilación condicional bajo OTHER_SWIFT_FLAGS, recordando añadir "-D" a la configuración. Por ejemplo, para compilar condicionalmente con un valor MYFLAG:

#if MYFLAG1 // stuff 1 #elseif MYFLAG2 // stuff 2 #else // stuff 3 #endif

El valor para agregar a la configuración -DMYFLAG

Ahora solo necesitamos pasar el valor MYFLAG a la nueva configuración. ¡Es hora de mover todos esos valores de compilación condicional!

Consulte el siguiente enlace para ver más características de Swift Build Settings en Xcode 8: http://www.miqu.me/blog/2016/07/31/xcode-8-new-build-settings-and-analyzer-improvements/



XCODE 9 Y ARRIBA

#if DEVELOP // #elseif PRODCTN // #else // #endif