Retire println () para la versión de lanzamiento iOS Swift

Me gustaría ignorar globalmente todas las llamadas a println() en mi código Swift si no estoy en una comstackción de depuración. No puedo encontrar instrucciones sólidas paso a paso para esto y agradecería una guía. ¿Hay alguna manera de hacer esto globalmente, o necesito rodear cada println() con println() #IF DEBUG/#ENDIF ?

La manera más simple es poner su propia función global frente a la println de Swift:

 func println(object: Any) { Swift.println(object) } 

Cuando llega el momento de detener el registro, simplemente comente el cuerpo de esa función:

 func println(object: Any) { // Swift.println(object) } 

O puede hacerlo de forma automática utilizando un condicional:

 func println(object: Any) { #if DEBUG Swift.println(object) #endif } 

EDITAR En Swift 2.0 println se cambia para print . Desafortunadamente ahora tiene un primer parámetro variado; esto es genial, pero significa que no puede anularlo fácilmente porque Swift no tiene un operador “splat”, por lo que no puede pasar un código variable (solo se puede crear literalmente). Pero puede hacer una versión reducida que funcione si, como suele ser el caso, está imprimiendo un solo valor:

 func print(items: Any..., separator: String = " ", terminator: String = "\n") { Swift.print(items[0], separator:separator, terminator: terminator) } 

En Swift 3, debe suprimir la etiqueta externa del primer parámetro:

 func print(_ items: Any..., separator: String = " ", terminator: String = "\n") { Swift.print(items[0], separator:separator, terminator: terminator) } 

Actualizado para Swift 4.x:

Con Swift 2.0 / 3.0 y Xcode 7/8 ahora fuera de beta, se han producido algunos cambios en la forma de desactivar la función de impresión en versiones de lanzamiento.

Hay algunos puntos importantes mencionados por @matt y @Nate Birkholz arriba que todavía son válidos.

  1. La función println() ha sido reemplazada por print()

  2. Para usar la macro #if DEBUG , debe definir “Swift Compiler – Custom Flags -Other Flags” para contener el valor -D DEBUG

  3. Recomendaría reemplazar la función Swift.print() en el ámbito global para que pueda usar la función print() como normal en su código, pero eliminará el resultado para comstackciones sin depuración. Aquí hay una firma de función que puede agregar en el scope global para hacer esto en Swift 2.0 / 3.0:

     func print(items: Any..., separator: String = " ", terminator: String = "\n") { #if DEBUG var idx = items.startIndex let endIdx = items.endIndex repeat { Swift.print(items[idx], separator: separator, terminator: idx == (endIdx - 1) ? terminator : separator) idx += 1 } while idx < endIdx #endif } 

Nota: Hemos establecido el separador predeterminado para que sea un espacio aquí, y el terminador predeterminado sea una nueva línea. Puede configurar esto de manera diferente en su proyecto si lo desea.

Espero que esto ayude.

Actualizar:

Por lo general, es preferible colocar esta función en el scope global, de modo que se encuentre frente a la función de print de Swift. Encuentro que la mejor manera de organizar esto es agregar un archivo de utilidad a su proyecto (como DebugOptions.Swift) donde puede ubicar esta función en el scope global.

A partir de Swift 3, el operador ++ quedará obsoleto. He actualizado el fragmento de arriba para reflejar este cambio.

El problema con todos estos enfoques, incluido el mío, es que no eliminan la sobrecarga de la evaluación de los argumentos de print . No importa cuál de ellos use, esto va a ser costoso:

 print(myExpensiveFunction()) 

La única solución decente es ajustar la llamada de impresión real en la comstackción condicional (supongamos que DEBUG está definido solo para comstackciones de depuración):

 #if DEBUG print(myExpensiveFunction()) #endif 

Eso, y solo eso, evita que se myExpensiveFunction a myExpensiveFunction en una versión de lanzamiento.

Sin embargo, puede retrasar la evaluación de un nivel mediante el uso de cierre automático . Por lo tanto, podría reescribir mi solución (esto es Swift 3) de esta manera:

 func print(_ item: @autoclosure () -> Any, separator: String = " ", terminator: String = "\n") { #if DEBUG Swift.print(item(), separator:separator, terminator: terminator) #endif } 

Esto resuelve el problema solo en el caso en el que está imprimiendo solo una cosa, que generalmente es cierta. Eso es porque el item() no se llama en el modo de lanzamiento. print(myExpensiveFunction()) deja de ser costoso, porque la llamada se envuelve en un cierre sin ser evaluada, y en el modo de lanzamiento, no se evaluará en absoluto.

Como se señaló, soy estudiante y necesito que las cosas se definan un poco más claramente para seguir. Después de mucha investigación, la secuencia que necesitaba seguir es:

Haga clic en el nombre del proyecto en la parte superior del Explorador de archivos a la izquierda de la ventana del proyecto de Xcode. Esta es la línea que tiene el nombre del proyecto, cuántos objectives de comstackción existen y la versión de iOS SDK.

Elija la pestaña Configuraciones de comstackción y desplácese hacia abajo hasta la sección ” Comstackdor Swift – Banderas personalizadas ” que se encuentra cerca de la parte inferior. Haga clic en la flecha hacia abajo junto a Otros indicadores para expandir la sección.

Haga clic en la línea Debug para seleccionarlo. Coloque el cursor del mouse sobre el lado derecho de la línea y haga doble clic. Aparecerá una vista de lista. Haga clic en el botón + en la parte inferior izquierda de la vista de lista para agregar un valor. Un campo de texto se activará.

En el campo de texto, ingrese el texto -D DEBUG y presione Return para confirmar la línea.

Agregue un nuevo archivo Swift a su proyecto. Tendrá que crear una clase personalizada para el archivo, por lo tanto, ingrese el texto en las siguientes líneas:

 class Log { var intFor : Int init() { intFor = 42 } func DLog(message: String, function: String = __FUNCTION__) { #if DEBUG println("\(function): \(message)") #endif } } 

Estaba teniendo problemas para que Xcode acepte hoy la clase, por lo que el init puede ser un poco más pesado de lo necesario.

Ahora necesitará hacer referencia a su clase personalizada en cualquier clase en la que pretenda usar la nueva función personalizada en lugar de println() Agregar esto como una propiedad en cada clase aplicable:

  let logFor = Log() 

Ahora puede reemplazar cualquier instancia de println() con logFor.DLog() . La salida también incluye el nombre de la función en la que se llamó a la línea.

Tenga en cuenta que dentro de las funciones de clase no podría llamar a la función a menos que haga una copia de la función como una función de clase en esa clase, y println() también sea un poco más flexible con la entrada, así que no podría usar esto en cada instancia en mi código.

Probado con Swift 2.1 y Xcode 7.1.1

Existe una manera fácil de excluir todas las declaraciones de impresión de las versiones de lanzamiento, una vez que sepa que el comstackdor Swift elimina las funciones vacías .

Nota al pie: En la era de Objective-C, había un pre-analizador que se podía usar para eliminar declaraciones NSLog antes de que el comstackdor iniciara, como se describe en mi respuesta aquí . Pero como Swift ya no tiene un pre-analizador, este enfoque ya no es válido.

Esto es lo que uso hoy en día como una función de registro avanzada y fácilmente configurable, sin tener que preocuparme por eliminarla en versiones de lanzamiento. Además, al establecer diferentes indicadores de comstackción, puede ajustar la información que se registra según sea necesario.

Puede modificar la función según sea necesario, ¡cualquier sugerencia para mejorarla es bienvenida!

 // Gobal log() function // // note that empty functions are removed by the Swift compiler -> use #if $endif to enclose all the code inside the log() // these log() statements therefore do not need to be removed in the release build ! // // to enable logging // // Project -> Build Settings -> Swift Compiler - Custom flags -> Other Swift flags -> Debug // add one of these 3 possible combinations : // // -D kLOG_ENABLE // -D kLOG_ENABLE -D kLOG_DETAILS // -D kLOG_ENABLE -D kLOG_DETAILS -D kLOG_THREADS // // you can just call log() anywhere in the code, or add a message like log("hello") // func log(message: String = "", filePath: String = #file, line: Int = #line, function: String = #function) { #if kLOG_ENABLE #if kLOG_DETAILS var threadName = "" #if kLOG_THREADS threadName = NSThread.currentThread().isMainThread ? "MAIN THREAD" : (NSThread.currentThread().name ?? "UNKNOWN THREAD") threadName = "[" + threadName + "] " #endif let fileName = NSURL(fileURLWithPath: filePath).URLByDeletingPathExtension?.lastPathComponent ?? "???" var msg = "" if message != "" { msg = " - \(message)" } NSLog("-- " + threadName + fileName + "(\(line))" + " -> " + function + msg) #else NSLog(message) #endif #endif } 

Aquí es donde establece los indicadores del comstackdor:

enter image description here

Un ejemplo de salida con todos los indicadores se ve así:

  2016-01-13 23:48:38.026 FoodTracker[48735:4147607] -- [MAIN THREAD] ViewController(19) -> viewDidLoad() - hello 

El código con el registro () se ve así:

  override func viewDidLoad() { log("hello") super.viewDidLoad() // Handle the text field's user input through delegate callbacks nameTextField.delegate = self } 

Aquí hay una función que uso, que funciona perfectamente en Swift 3:

 func gLog( _ object: @autoclosure() -> T, _ file: String = #file, _ function: String = #function, _ line: Int = #line) { #if DEBUG let value = object() let stringRepresentation: String if let value = value as? CustomDebugStringConvertible { stringRepresentation = value.debugDescription } else if let value = value as? CustomStringConvertible { stringRepresentation = value.description } else { fatalError("gLog only works for values that conform to CustomDebugStringConvertible or CustomStringConvertible") } let fileURL = NSURL(string: file)?.lastPathComponent ?? "Unknown file" let queue = Thread.isMainThread ? "UI" : "BG" let gFormatter = DateFormatter() gFormatter.dateFormat = "HH:mm:ss:SSS" let timestamp = gFormatter.string(from: Date()) print("✅ \(timestamp) {\(queue)} \(fileURL) > \(function)[\(line)]: " + stringRepresentation + "\n") #endif } 

Aquí hay un ejemplo de la salida que genera:

captura de pantalla de salida

Explicación:

  • la marca de verificación verde se usa para permitirle ver rápidamente sus mensajes de impresión (gLog) en la consola, donde a veces se pueden perder en un mar de otros mensajes

  • la marca de hora / fecha

  • el hilo en el que se está ejecutando, en mi caso es el MainThread (que yo llamo UI), o no el MainThread (que llamo BG, para el hilo de fondo)

  • el nombre del archivo en el que reside el mensaje gLog

  • la función dentro del archivo en el que reside el mensaje gLog

  • el número de línea del mensaje gLog

  • el mensaje gLog real que desea imprimir

Espero que esto sea útil para otra persona!

XCode 8 introdujo algunas nuevas configuraciones de comstackción .
En particular, uno referido a Active Comstacktion Conditions hace de forma similar lo que hicieron las configuraciones de Otros indicadores .

“Condiciones de comstackción activa” es una nueva configuración de comstackción para pasar indicadores de comstackción condicional al comstackdor de Swift.

Según XCode 8 (probado en 8.3.2), obtendrá esto de manera predeterminada:

enter image description here

Entonces, sin ninguna configuración, puede escribir lo siguiente:

 #if DEBUG print("⚠️ Something weird happened") #endif 

Le recomiendo encarecidamente que si utiliza este enfoque ampliamente, cree una clase / estructura / función que ajuste esta lógica de registro. Es posible que desee extender esto más adelante.

Incluso más simple, después de asegurarse de que -D DEBUG esté configurado para la configuración de comstackción Debug OTHER_SWIFT_FLAGS :

 #if !DEBUG func println(object: Any) {} func print(object: Any){} #endif 

En Swift 2 / Xcode 7 ya no necesita / usa println pero es posible que desee agregar líneas para:

 func print(_ items: Any..., separator separator: String = default, terminator terminator: String = default) 

Puede definir debug_println cuyos contenidos serían aproximadamente:

 #if DEBUG println() #endif 

Mi solución es usar este código en AppDelegate antes de la clase

 // Disable console log in live app #if !arch(x86_64) && !arch(i386) public func debugPrint(items: Any..., separator: String = " ", terminator: String = "\n") { } public func print(_ items: Any..., separator: String = " ", terminator: String = "\n") { } #endif class AppDelegate: UIResponder, UIApplicationDelegate { // App Delegate Code } 

para mi solución lo hago simple

 import UIKit class DLog: NSObject { init(title:String, log:Any) { #if DEBUG print(title, log) #endif } } 

luego para mostrarlo solo llame

 _ = DLog(title:"any title", log:Any) 

Arriba, todas son buenas respuestas. Simplemente podría usar Swift.debugPrint() para apagar todas las impresiones en el modo de lanzamiento.