2011-07-20 18 views
6

Cuando escribo algo, la mitad del esfuerzo tiende a incluir una salida de depuración clara y concisa, o la funcionalidad que se puede habilitar/deshabilitar cuando ese algo necesita depuración.Evitando problemas con depuración en el código

Un ejemplo de la funcionalidad de depuración es una clase de descarga en la que puedo activar un #define que hace que "pretenda" descargar el archivo y simplemente devolverme el que ya tengo. De esa forma puedo probar para ver qué sucede cuando un usuario descarga un archivo, sin tener que esperar a que la red tome físicamente el archivo cada vez. Esta es una gran funcionalidad, pero el código se vuelve más complicado con los #ifdefs.

finalmente termino con un montón de #define s como

// #define DEBUG_FOOMODULE_FOO 
// #define DEBUG_BARMODULE_THINGAMAJIG 
// ... 

cuales no están comentadas por las cosas que quiero mirar. El código en sí resulta algo así como

- (void)something 
{ 
    #ifdef DEBUG_FOOMODULE_FOO 
    DebugLog(@"something [x = %@]", x); 
    #endif 
    // ... 
    #ifdef DEBUG_FOOMODULE_MOO 
    // etc 
} 

Esto funciona muy bien para la escritura/el mantenimiento del código, pero no hace nada por la aparición del código.

¿Cómo se escribe "cosas" de depuración a largo plazo sin esfuerzo sobre la marcha?

Nota: No estoy hablando solamente de NSLogging aquí ... También estoy hablando de cosas como la descarga de simulación anterior.

+0

Curioso: ¿hay algún problema al dejar declaraciones 'NSLog' en una compilación de lanzamiento? ¿Duele el rendimiento, llena los registros del dispositivo o proporciona resultados no deseados? –

+0

Apple menciona que debe eliminar las entradas de NSLog de su código al liberarlo, así que creo que sí. (Realmente no puedo encontrar esto, pero estoy casi seguro de haberlo leído en developer.apple.com en algún lugar cuando comencé a codificar). – Kalle

+0

Creo que recuerdo haber leído eso en alguna parte también. Probablemente no sea una mala idea. Tal vez la próxima versión de la aplicación agregue la macro y busque/reemplace. –

Respuesta

2

leí varias bibliotecas antes de escribir mi propia y vi dos enfoques: funciones + C macro (NSLogger) o macro + Singleton (GTMLogger, Cocoa Lumberjack)

Escribí mi implementación ingenua here usando macro + singleton. Lo hago durante el tiempo de ejecución:

[Logger singleton].logThreshold = kDebug; 
trace(@"hi %@",@"world); // won't show 
debug(@"hi %@",@"world); 

Puede hacer lo mismo para paquetes en lugar de niveles de registro. Si quiero que se vaya, cambio las #defines. Aquí está el código que participan:

#define trace(args...) [[Logger singleton] debugWithLevel:kTrace line:__LINE__ funcName:__PRETTY_FUNCTION__ message:args]; 

if (level>=logThreshold){ 
    // ... 
} 

Si quieres algo look más sofisticado en leñador, que tiene una instalación de clase registro para cambiar el registro para algunas clases.

+0

Interesante. Definitivamente los investigaré, gracias! – Kalle

+0

Miró un poco. Supongo que el mayor problema es que a veces también incluyo un código especial para la depuración que está dentro de esas # definiciones. Estoy empezando a darme cuenta de que este es quizás un mal enfoque, sin importar cómo lo hagas ...: / – Kalle

0

Para su caso, podría tener macros de registro separadas, digamos MooLog y FooLog, que todas compilan condicionalmente en base a banderas separadas.

#ifdef DEBUG_FOO 
# define FooLog(fmt, ...) NSLog((@"%s [Line %d] " fmt), __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__); 
#else 
# define FooLog(...) 
#endif 

#ifdef DEBUG_MOO 
# define MooLog(fmt, ...) NSLog((@"%s [Line %d] " fmt), __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__); 
#else 
# define MooLog(...) 
#endif 

Su lógica compleja en todas partes ahora se convierte en esto:

- (void)something 
{ 
    // This only gets logged if the "DEBUG_FOO" flag is set. 
    FooLog(@"something [x = %@]", x); 
    // This only gets logged if the "DEBUG_MOO" flag is set. 
    MooLog(@"Something else [y = %@]", y); 
} 
+0

Bueno, lo simplifiqué a NSLog en el código anterior, pero ya estoy usando código que hace esto. Lo que estoy preguntando es dónde se puede habilitar/deshabilitar "módulos de depuración". Creo que podría escribir un montón de funciones #define para cada uno de esos módulos para reducir el # if, pero ¿no hay alguna forma mejor de hacerlo? : | – Kalle

1

Tener dos funciones y luego seleccionarlas adecuadamente ya sea en tiempo de ejecución o cuando compilar me parece una aproximación limpia. Esto hace posible tener un archivo download.c y un archivo download_debug.c con las mismas funciones excepto con diferentes implementaciones. Luego, vincula con la apropiada si estás compilando con -DDEBUG o no.

De lo contrario, el uso de punteros a funciones funciona también para las funciones de selección de tiempo de ejecución.

Si insistes en tener código de depuración intercalado en todas tus funciones, estás prácticamente preparándote para un lío :) Pero, por supuesto, puedes dividir esos fragmentos en funciones separadas y luego hacer lo anterior (o hacerlos) no-ops como en el ejemplo de DLog).

Cuestiones relacionadas