2009-06-09 8 views
434

Estoy haciendo una presentación sobre la depuración en Xcode y me gustaría obtener más información sobre el uso eficiente de NSLog.¿Cómo imprimir el nombre del método y el número de línea y deshabilitar condicionalmente NSLog?

En particular, tengo dos preguntas:

  • hay una manera fácil de NSLog nombre/número de la línea del método actual?
  • ¿hay alguna manera de "deshabilitar" todos los NSLogs fácilmente antes de compilar para el código de versión?
+12

** primera pregunta dónde favoritos (estrella) son más que upvotes ... ** 1 .. –

Respuesta

572

Éstos son algunos macros útiles alrededor NSLog que utilizan una gran cantidad:

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

// ALog always displays output regardless of the DEBUG setting 
#define ALog(fmt, ...) NSLog((@"%s [Line %d] " fmt), __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__) 

La macro dlog se utiliza para salida sólo cuando se establece la variable de depuración (-DDEBUG en banderas C de los proyectos para la confirguration depuración) .

ALog siempre mostrará texto (como el NSLog normal).

La salida (por ejemplo AInicie la sesión (@ "Hola mundo")) se verá así:

-[LibraryController awakeFromNib] [Line 364] Hello world 
+0

¿Por qué tiene un ##?Pensé que era para pegar argumentos juntos, pero no te estás pegando a nada. – Casebash

+1

Esto evita la posible macro expansión de los argumentos – diederikh

+0

Eso puede suceder con las macros en general; algunas macros producen líneas múltiples. Solo otro argumento para usar siempre llaves ;-). – diederikh

72
NSLog(@"%s %d %s %s", __FILE__, __LINE__, __PRETTY_FUNCTION__, __FUNCTION__); 

salidas archivo de nombre, número de línea, y el nombre de la función:

/proj/cocoa/cdcli/cdcli.m 121 managedObjectContext managedObjectContext 

__FUNCTION__ en C++ muestra nombre revuelto __PRETTY_FUNCTION__ muestra buen nombre de la función, en el cacao que tienen el mismo aspecto.

no estoy seguro de lo que es la forma correcta de desactivar NSLog, lo hice:

#define NSLog 

Y ninguna salida de registro se presentó, sin embargo, no sé si esto tiene algún efecto secundario.

16

Mi respuesta a this question podría ayudar, parece que es similar a la Diederik cocinado. También puede reemplazar la llamada al NSLog() con una instancia estática de su propia clase de registro personalizado, de esa manera puede agregar un indicador de prioridad para los mensajes de depuración/advertencia/error, enviar mensajes a un archivo o base de datos, así como a la consola, o casi cualquier otra cosa que se te ocurra.

#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 
+0

Porque eludió el especificador de formato '% s', que Apple está tratando de despreciar y evitó' -Wcstring-format-directive' Advertencia de Clang recientemente presentada en 2015. – Jeff

11

Para complementar las respuestas anteriores, puede ser bastante útil utilizar un reemplazo para NSLog en ciertas situaciones, especialmente cuando se depura. Por ejemplo, deshacerse de toda la información de fecha/nombre de proceso/ID en cada línea puede hacer que la salida sea más legible y más rápida de arrancar.

El siguiente enlace proporciona bastante munición útil para hacer que el registro simple sea mucho más agradable.

http://cocoaheads.byu.edu/wiki/a-different-nslog

20

Aquí una gran colección de constantes de depuración que utilizamos. Disfrutar.

// Uncomment the defitions to show additional info. 

// #define DEBUG 

// #define DEBUGWHERE_SHOWFULLINFO 

// #define DEBUG_SHOWLINES 
// #define DEBUG_SHOWFULLPATH 
// #define DEBUG_SHOWSEPARATORS 
// #define DEBUG_SHOWFULLINFO 


// Definition of DEBUG functions. Only work if DEBUG is defined. 
#ifdef DEBUG 

    #define debug_separator() NSLog(@"────────────────────────────────────────────────────────────────────────────"); 

    #ifdef DEBUG_SHOWSEPARATORS 
     #define debug_showSeparators() debug_separator(); 
    #else 
     #define debug_showSeparators() 
    #endif 

    /// /// /// ////// ///// 

    #ifdef DEBUG_SHOWFULLPATH 
     #define debug_whereFull() debug_showSeparators(); NSLog(@"Line:%d : %s : %s", __LINE__,__FILE__,__FUNCTION__); debug_showSeparators(); 
    #else 
     #define debug_whereFull() debug_showSeparators(); NSLog(@"Line:%d : %s : %s", __LINE__,[ [ [ [NSString alloc] initWithBytes:__FILE__ length:strlen(__FILE__) encoding:NSUTF8StringEncoding] lastPathComponent] UTF8String ] ,__FUNCTION__); debug_showSeparators(); 
    #endif 

    /// /// /// ////// ///// 

    #define debugExt(args,...) debug_separator(); debug_whereFull(); NSLog(args, ##__VA_ARGS__); debug_separator(); 

    /// /// /// ////// ///// Debug Print Macros 

    #ifdef DEBUG_SHOWFULLINFO 
     #define debug(args,...) debugExt(args, ##__VA_ARGS__); 
    #else 
     #ifdef DEBUG_SHOWLINES 
      #define debug(args,...) debug_showSeparators(); NSLog([ NSString stringWithFormat:@"Line:%d : %@", __LINE__, args ], ##__VA_ARGS__); debug_showSeparators(); 
     #else 
      #define debug(args,...) debug_showSeparators(); NSLog(args, ##__VA_ARGS__); debug_showSeparators(); 
     #endif 
    #endif 

    /// /// /// ////// ///// Debug Specific Types 

    #define debug_object(arg) debug(@"Object: %@", arg); 
    #define debug_int(arg) debug(@"integer: %i", arg); 
    #define debug_float(arg) debug(@"float: %f", arg); 
    #define debug_rect(arg) debug(@"CGRect (%f, %f, %f, %f)", arg.origin.x, arg.origin.y, arg.size.width, arg.size.height); 
    #define debug_point(arg) debug(@"CGPoint (%f, %f)", arg.x, arg.y); 
    #define debug_bool(arg) debug(@"Boolean: %@", (arg == YES ? @"YES" : @"NO")); 

    /// /// /// ////// ///// Debug Where Macros 

    #ifdef DEBUGWHERE_SHOWFULLINFO 
     #define debug_where() debug_whereFull(); 
    #else 
     #define debug_where() debug(@"%s",__FUNCTION__); 
    #endif 

    #define debug_where_separators() debug_separator(); debug_where(); debug_separator(); 

    /// /// /// ////// ///// 

#else 
    #define debug(args,...) 
    #define debug_separator() 
    #define debug_where() 
    #define debug_where_separators() 
    #define debug_whereFull() 
    #define debugExt(args,...) 
    #define debug_object(arg) 
    #define debug_int(arg) 
    #define debug_rect(arg) 
    #define debug_bool(arg) 
    #define debug_point(arg) 
    #define debug_float(arg) 
#endif 
13

Desactivación de todos los NSLogs, para alguien alérgico a las macros, esto es algo que se puede compilar también:

void SJLog(NSString *format,...) 
{ 
    if(LOG) 
    { 
     va_list args; 
     va_start(args,format); 
     NSLogv(format, args); 
     va_end(args); 
    } 
} 

Y, lo utilizan casi como NSLog:

SJLog(@"bye bye NSLogs !"); 

A partir de este blog: http://whackylabs.com/rants/?p=134

140

He tomado DLog y ALog desde arriba, y agregó ULog, lo que genera un mensaje de UIAlertView.

En resumen:

  • DLog voluntad salida como NSLog sólo cuando se establece la variable DEBUG
  • ALog habrá siempre una salida como NSLog
  • ULog mostrará el UIAlertView sólo cuando la variable de depuración se establece
 
#ifdef DEBUG 
# define DLog(fmt, ...) NSLog((@"%s [Line %d] " fmt), __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__); 
#else 
# define DLog(...) 
#endif 
#define ALog(fmt, ...) NSLog((@"%s [Line %d] " fmt), __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__); 
#ifdef DEBUG 
# define ULog(fmt, ...) { UIAlertView *alert = [[UIAlertView alloc] initWithTitle:[NSString stringWithFormat:@"%s\n [Line %d] ", __PRETTY_FUNCTION__, __LINE__] message:[NSString stringWithFormat:fmt, ##__VA_ARGS__] delegate:nil cancelButtonTitle:@"Ok" otherButtonTitles:nil]; [alert show]; } 
#else 
# define ULog(...) 
#endif 

Esto es lo que parece:

Debug UIAlertView

+1 Diederik

+0

Voy a extender mi código ALog + DLog también con ULog. Muy útil. – neoneye

+0

Este código causa un error variable no utilizado en Xcode 5.1 si no se ejecuta en DEBUG :( – yonix

+0

¿Por qué algunas de las directivas #define terminan con un punto y coma? – Monstieur

4

Nueva Además de dlog. En lugar de eliminar por completo la depuración de la aplicación lanzada, solo desactívela. Cuando el usuario tiene problemas, lo que requeriría depuración, simplemente indique cómo habilitar la depuración en la aplicación lanzada y solicitar datos de registro por correo electrónico.

versión corta: crear variable global (sí, solución perezosa y simple) y modificar dlog así:

BOOL myDebugEnabled = FALSE; 
#define DLog(fmt, ...) if (myDebugEnabled) NSLog((@"%s [Line %d] " fmt), __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__); 

Respuesta larga en Jomnius iLessons iLearned: How to Do Dynamic Debug Logging in Released Application

19

Hay un nuevo truco que ningún responder dar. Puede usar printf en su lugar NSLog. Esto le dará un registro limpio:

Con NSLog a hacer las cosas de esta manera:

2011-11-03 13:43:55.632 myApp[3739:207] Hello Word 

Pero con printf se obtiene solamente:

Hello World 

Usar este código

#ifdef DEBUG 
    #define NSLog(FORMAT, ...) fprintf(stderr,"%s\n", [[NSString stringWithFormat:FORMAT, ##__VA_ARGS__] UTF8String]); 
#else 
    #define NSLog(...) {}    
#endif 
5

construyendo en la parte superior de las respuestas anteriores, esto es lo que plagiado y se me ocurrió . También se agregó el registro de memoria.

#import <mach/mach.h> 

#ifdef DEBUG 
# define DebugLog(fmt, ...) NSLog((@"%s(%d) " fmt), __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__); 
#else 
# define DebugLog(...) 
#endif 


#define AlwaysLog(fmt, ...) NSLog((@"%s(%d) " fmt), __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__); 


#ifdef DEBUG 
# define AlertLog(fmt, ...) { \ 
    UIAlertView *alert = [[UIAlertView alloc] \ 
      initWithTitle : [NSString stringWithFormat:@"%s(Line: %d) ", __PRETTY_FUNCTION__, __LINE__]\ 
        message : [NSString stringWithFormat : fmt, ##__VA_ARGS__]\ 
       delegate : nil\ 
     cancelButtonTitle : @"Ok"\ 
     otherButtonTitles : nil];\ 
    [alert show];\ 
} 
#else 
# define AlertLog(...) 
#endif 



#ifdef DEBUG 
# define DPFLog NSLog(@"%s(%d)", __PRETTY_FUNCTION__, __LINE__);//Debug Pretty Function Log 
#else 
# define DPFLog 
#endif 


#ifdef DEBUG 
# define MemoryLog {\ 
    struct task_basic_info info;\ 
    mach_msg_type_number_t size = sizeof(info);\ 
    kern_return_t e = task_info(mach_task_self(),\ 
            TASK_BASIC_INFO,\ 
            (task_info_t)&info,\ 
            &size);\ 
    if(KERN_SUCCESS == e) {\ 
     NSNumberFormatter *formatter = [[NSNumberFormatter alloc] init]; \ 
     [formatter setNumberStyle:NSNumberFormatterDecimalStyle]; \ 
     DebugLog(@"%@ bytes", [formatter stringFromNumber:[NSNumber numberWithInteger:info.resident_size]]);\ 
    } else {\ 
     DebugLog(@"Error with task_info(): %s", mach_error_string(e));\ 
    }\ 
} 
#else 
# define MemoryLog 
#endif 
11

Es fácil cambiar sus NSLogs existentes para mostrar el número de línea y la clase desde la que se llaman. Añadir una línea de código a su archivo de prefijo:

#define NSLog(__FORMAT__, ...) NSLog((@"%s [Line %d] " __FORMAT__), __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__) 
+2

¡Esto es genial! ¿Cómo haría esto en breve? –

+0

@AddisDev Me gusta más esto. Muy limpio y simple. Solo uso NSLog. No tengo idea de qué DLog y ULog Gracias. Hasta votó ... –

+0

@AddisDev Realmente no entiendo por qué Apple no agrega estos datos de vital importancia a NSLog() de forma predeterminada? Bizarre ... –

3

Desde hace algún tiempo he estado usando un sitio de macros adoptado de varias arriba. Mi enfoque en el inicio de sesión en la consola, con énfasis en controlado & verbosidad filtrada; Si no te importa una gran cantidad de líneas de registro, pero desea cambiar fácilmente lotes de ellas en &, entonces puede que le resulte útil.

En primer lugar, sustituir opcionalmente NSLog con printf como se describe por @Rodrigo anteriormente

#define NSLOG_DROPCHAFF//comment out to get usual date/time ,etc:2011-11-03 13:43:55.632 myApp[3739:207] Hello Word 

#ifdef NSLOG_DROPCHAFF 
#define NSLog(FORMAT, ...) printf("%s\n", [[NSString stringWithFormat:FORMAT, ##__VA_ARGS__] UTF8String]); 
#endif 

A continuación, modificador de registro encendido o apagado.

#ifdef DEBUG 
#define LOG_CATEGORY_DETAIL// comment out to turn all conditional logging off while keeping other DEBUG features 
#endif 

en el bloque principal, definir varios categorías correspondientes a los módulos en su aplicación. Defina también un nivel de registro por encima del cual no se invocarán las llamadas de registro. A continuación, definir varios sabores de la producción NSLog

#ifdef LOG_CATEGORY_DETAIL 

    //define the categories using bitwise leftshift operators 
    #define kLogGCD (1<<0) 
    #define kLogCoreCreate (1<<1) 
    #define kLogModel (1<<2) 
    #define kLogVC (1<<3) 
    #define kLogFile (1<<4) 
    //etc 

    //add the categories that should be logged... 
    #define kLOGIFcategory kLogModel+kLogVC+kLogCoreCreate 

    //...and the maximum detailLevel to report (use -1 to override the category switch) 
    #define kLOGIFdetailLTEQ 4 

    // output looks like this:"-[AppDelegate myMethod] log string..." 
    # define myLog(category,detailLevel,format, ...) if(detailLevel<0 || ((category&kLOGIFcategory)&&detailLevel<= kLOGIFdetailLTEQ)) {NSLog((@"%s " format), __PRETTY_FUNCTION__, ##__VA_ARGS__);} 

    // output also shows line number:"-[AppDelegate myMethod][l17] log string..." 
    # define myLogLine(category,detailLevel,format, ...) if(detailLevel<0 || ((category&kLOGIFcategory)&&detailLevel<= kLOGIFdetailLTEQ)) {NSLog((@"%s[l%i] " format), __PRETTY_FUNCTION__,__LINE__ ,##__VA_ARGS__);} 

    // output very simple:" log string..." 
    # define myLogSimple(category,detailLevel,format, ...) if(detailLevel<0 || ((category&kLOGIFcategory)&&detailLevel<= kLOGIFdetailLTEQ)) {NSLog((@"" format), ##__VA_ARGS__);} 

    //as myLog but only shows method name: "myMethod: log string..." 
    // (Doesn't work in C-functions) 
    # define myLog_cmd(category,detailLevel,format,...) if(detailLevel<0 || ((category&kLOGIFcategory)&&detailLevel<= kLOGIFdetailLTEQ)) {NSLog((@"%@: " format), NSStringFromSelector(_cmd), ##__VA_ARGS__);} 

    //as myLogLine but only shows method name: "myMethod>l17: log string..." 
    # define myLog_cmdLine(category,detailLevel,format, ...) if(detailLevel<0 || ((category&kLOGIFcategory)&&detailLevel<= kLOGIFdetailLTEQ)) {NSLog((@"%@>l%i: " format), NSStringFromSelector(_cmd),__LINE__ , ##__VA_ARGS__);} 

    //or define your own... 
    // # define myLogEAGLcontext(category,detailLevel,format, ...) if(detailLevel<0 || ((category&kLOGIFcategory)&&detailLevel<= kLOGIFdetailLTEQ)) {NSLog((@"%s>l%i (ctx:%@)" format), __PRETTY_FUNCTION__,__LINE__ ,[EAGLContext currentContext], ##__VA_ARGS__);} 

#else 
    # define myLog_cmd(...) 
    # define myLog_cmdLine(...) 
    # define myLog(...) 
    # define myLogLine(...) 
    # define myLogSimple(...) 
    //# define myLogEAGLcontext(...) 
#endif 

Por lo tanto, la configuración actual de kLOGIFcategory y kLOGIFdetailLTEQ, una llamada como

myLogLine(kLogVC, 2, @"%@",self); 

imprimirá pero esto no

myLogLine(kLogGCD, 2, @"%@",self);//GCD not being printed 

ni tampoco

myLogLine(kLogGCD, 12, @"%@",self);//level too high 

Si desea anular la configuración de una llamada de registro individual, utilice un nivel negativo:

myLogLine(kLogGCD, -2, @"%@",self);//now printed even tho' GCD category not active. 

encuentro los pocos caracteres adicionales de escribir cada línea valen como pueda a continuación

  1. Active o desactive una categoría completa de comentarios (p. Ej. Sólo reportar esas llamadas marcadas Modelo)
  2. informe sobre los detalles finos con los números de nivel superior o sólo las llamadas más importantes marcados con los números más bajos

Estoy seguro de que muchos encontrarán esto un poco de una exageración, pero sólo en caso de que alguien encuentre conviene a sus propósitos ..

6

es simple, por ejemplo

-(void)applicationWillEnterForeground:(UIApplication *)application {

NSLog(@"%s", __PRETTY_FUNCTION__); 

}

Salida: - [AppDelegate applicationWillEnterForeground:]

Cuestiones relacionadas