iphone - ¿Es cierto que uno no debería usar NSLog() en el código de producción?
objective-c (12)
Coloque estas 3 líneas al final del archivo -prefix.pch:
#ifndef DEBUG
#define NSLog(...) /* suppress NSLog when in release mode */
#endif
No necesita definir nada en su proyecto, porque DEBUG
se define en su configuración de compilación de forma predeterminada cuando crea su proyecto.
Me dijeron esto algunas veces en este mismo sitio, pero quería asegurarme de que este es realmente el caso.
Esperaba poder rociar llamadas de función NSLog a través de mi código, y que Xcode / gcc quitaría automáticamente esas llamadas al construir mis versiones de Release / Distribution.
¿Debería evitar usar esto? Si es así, ¿qué alternativas son más comunes entre los programadores experimentados de Objective-C?
Como se indicó en otras respuestas, puede usar un #define para modificar si NSLog se usa o no en el momento de la compilación.
Sin embargo, una forma más flexible es usar una biblioteca de registro como Cocoa Lumberjack, que le permite cambiar si también se registra algo en el tiempo de ejecución.
En su código, reemplace NSLog por DDLogVerbose o DDLogError, etc., agregue un #import para las definiciones de macro, etc. y configure los registradores, a menudo en el método applicationDidFinishLaunching.
Para tener el mismo efecto que NSLog, el código de configuración es
[DDLog addLogger:[DDASLLogger sharedInstance]];
[DDLog addLogger:[DDTTYLogger sharedInstance]];
Desde un punto de vista de seguridad, depende de lo que se está registrando. Si NSLog
(u otros registradores) está escribiendo información confidencial, entonces debe eliminar el registrador en el código de producción.
Desde el punto de vista de la auditoría, el auditor no quiere ver cada uso de NSLog
para asegurarse de que no esté registrando información confidencial. Él / ella simplemente le dirá que retire el registrador.
Yo trabajo con ambos grupos. Nosotros auditamos el código, escribimos las guías de codificación, etc. Nuestra guía requiere que el registro esté deshabilitado en el código de producción. Entonces los equipos internos saben que no deben intentarlo;)
También rechazaremos una aplicación externa que inicia sesión en producción porque no queremos aceptar el riesgo asociado con la filtración accidental de información sensible. No nos importa lo que el desarrollador nos diga. Simplemente no vale nuestro tiempo para investigar.
Y recuerde, definimos ''sensible'', y no el desarrollador;)
También percibo una aplicación que realiza muchos inicios de sesión como una aplicación lista para implosionar. Hay una razón por la que se realiza / necesita mucho registro, y generalmente no es estabilidad. Está a la altura de los hilos ''watchdog'' que reinician servicios colgados.
Si nunca ha pasado por una revisión de Arquitectura de Seguridad (SecArch), este es el tipo de cosas que consideramos.
Estoy de acuerdo con Matthew. No hay nada malo con NSLog en el código de producción. De hecho, puede ser útil para el usuario. Dicho esto, si la única razón por la que está utilizando NSLog es para ayudar a depurar, entonces, sí, eso debe eliminarse antes de su lanzamiento.
Además, como ha etiquetado esto como una pregunta de iPhone, NSLog toma recursos, que es algo que el iPhone tiene muy poco de. Si está iniciando NSLogging en el iPhone, eso le quita el tiempo de procesador de su aplicación. Úsalo con sabiduría.
La simple verdad es que NSLog es simplemente lento.
¿Pero por qué? Para responder a esa pregunta, descubramos qué hace NSLog, y luego cómo lo hace.
¿Qué hace NSLog exactamente?
NSLog hace 2 cosas:
Escribe mensajes de registro en la instalación de registro del sistema Apple (asl). Esto permite que los mensajes de registro se muestren en Console.app. También verifica si la corriente stderr de la aplicación va a un terminal (como cuando la aplicación se ejecuta a través de Xcode). Si es así, escribe el mensaje de registro en stderr (para que aparezca en la consola de Xcode).
Escribir a STDERR no suena difícil. Eso se puede lograr con fprintf y la referencia del descriptor de archivo stderr. ¿Pero qué hay de asl?
La mejor documentación que he encontrado sobre ASL es una publicación de 10 partes del blog de Peter Hosey: link
Sin entrar en demasiados detalles, lo más destacado (en lo que respecta al rendimiento) es este:
Para enviar un mensaje de registro a la instalación de ASL, básicamente se abre una conexión de cliente con el daemon de ASL y se envía el mensaje. PERO - cada hilo debe usar una conexión de cliente separada. Por lo tanto, para estar seguro de subprocesos, cada vez que se invoca NSLog abre una nueva conexión de cliente asl, envía el mensaje y luego cierra la conexión.
Las llamadas NSLog se pueden dejar en el código de producción, pero solo deberían estar disponibles para casos verdaderamente excepcionales, o la información que se desea registrar en el registro del sistema.
Las aplicaciones que ensucian el registro del sistema son molestas y parecen poco profesionales.
Las macros de preprocesador son realmente geniales para la depuración. No hay nada malo con NSLog (), pero es simple definir su propia función de registro con una mejor funcionalidad. Este es el que uso, incluye el nombre del archivo y el número de línea para facilitar el seguimiento de las declaraciones de registro.
#define DEBUG_MODE
#ifdef DEBUG_MODE
#define DebugLog( s, ... ) NSLog( @"<%p %@:(%d)> %@", self, [[NSString stringWithUTF8String:__FILE__] lastPathComponent], __LINE__, [NSString stringWithFormat:(s), ##__VA_ARGS__] )
#else
#define DebugLog( s, ... )
#endif
Me pareció más fácil poner esta declaración completa en el encabezado prefijo en lugar de su propio archivo. Si quisieras, podrías construir un sistema de registro más complicado haciendo que DebugLog interactúe con los objetos Objective-C normales. Por ejemplo, puede tener una clase de registro que escribe en su propio archivo de registro (o base de datos) e incluye un argumento de "prioridad" que puede establecer en tiempo de ejecución, para que los mensajes de depuración no se muestren en su versión de lanzamiento, pero los mensajes de error son si hiciera esto, podría hacer DebugLog (), WarningLog (), y así sucesivamente).
Ah, y tenga en cuenta que #define DEBUG_MODE
se puede reutilizar en diferentes lugares de su aplicación. Por ejemplo, en mi aplicación lo uso para desactivar las comprobaciones de las claves de licencia y solo permitir que la aplicación se ejecute si es antes de una fecha determinada. Esto me permite distribuir una copia beta de tiempo limitado y completamente funcional con un mínimo esfuerzo de mi parte.
No debería ser innecesariamente prolijo con printf o NSLog en el código de lanzamiento. Intenta solo hacer un printf o NSLog si la aplicación tiene algo malo, IE es un error irrecuperable.
No puedo comentar la respuesta de Marc Charbonneau , así que lo publicaré como respuesta.
Además de agregar la macro a su encabezado precompilado, puede usar las configuraciones de compilación de Target para controlar la definición (o falta de definición) de DEBUG_MODE
.
Si selecciona la configuración activa " Depuración ", se DEBUG_MODE
y la macro se expandirá a la definición completa de NSLog
.
La selección de la configuración activa " Liberar " no definirá DEBUG_MODE
y su NSLog
ging se omite de la versión de lanzamiento.
Pasos:
- Target> Obtener información
- Pestaña Construir
- Buscar "Macros de preprocesador" (o
GCC_PREPROCESSOR_DEFINITIONS
) - Seleccione Configuración: Depurar
- Editar definición en este nivel
- Agregar
DEBUG_MODE=1
- Seleccionar configuración: lanzamiento
- confirmar
DEBUG_MODE
no está establecido enGCC_PREPROCESSOR_DEFINITIONS
si omite el carácter ''='' en la definición, obtendrá un error del preprocesador
Además, pegue este comentario (que se muestra debajo) encima de la definición de la macro para recordarle de dónde proviene la definición DEBUG_MACRO
;)
// Target > Get Info > Build > GCC_PREPROCESSOR_DEFINITIONS
// Configuration = Release: <empty>
// = Debug: DEBUG_MODE=1
Recomiendo usar TestFlight para el registro (gratis). Su método anulará NSLog (utilizando una macro) y le permitirá activar / desactivar el registro en su servidor, el registro del sistema Apple y el registro STDERR, para todas sus llamadas existentes a NSLog. Lo bueno de esto es que aún puede revisar sus mensajes de registro para las aplicaciones implementadas en probadores y aplicaciones implementadas en la App Store, sin que los registros aparezcan en el registro del sistema del usuario. Lo mejor de ambos mundos.
Tenga en cuenta que NSLogs puede ralentizar la UI / subproceso principal. Lo mejor es eliminarlos de compilaciones de lanzamiento a menos que sea absolutamente necesario.
EDITAR: El método publicado por , y traído a mi atención por sho , es mucho mejor que este.
He eliminado la parte de mi respuesta que sugería usar una función vacía para deshabilitar el inicio de sesión cuando el modo de depuración está deshabilitado. La parte que trata de establecer una macro de preprocesador automático sigue siendo relevante, por lo que permanece. También edité el nombre de la macro del preprocesador para que se ajuste mejor a la respuesta de Marc Charbonneau.
Para lograr el comportamiento automático (y esperado) en Xcode:
En la configuración del proyecto, vaya a la pestaña "Generar" y seleccione la configuración "Depurar". Busque la sección "Macros de preprocesador" y agregue una macro llamada DEBUG_MODE
.
...
EDITAR: Vea la respuesta de Marc Charbonneau para la forma correcta de activar y desactivar el registro con la macro DEBUG_MODE
.