objective c - ¿Cómo imprimir el nombre del método y el número de línea y desactivar condicionalmente NSLog?
objective-c cocoa (13)
Aquí hay algunas macros útiles alrededor de NSLog que uso mucho:
#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 usa solo para generar resultados cuando la variable DEBUG se establece (-DDEBUG en los indicadores C de los proyectos para la confirmación de depuración).
ALog siempre generará texto (como el NSLog normal).
La salida (por ejemplo, ALog (@ "Hello world")) se verá así:
-[LibraryController awakeFromNib] [Line 364] Hello world
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.
En particular, tengo dos preguntas:
- ¿hay una manera de NSLog fácilmente el nombre / número de línea del método actual?
- ¿hay una manera de "deshabilitar" todos los NSLogs fácilmente antes de compilar para el código de lanzamiento?
Aquí una gran colección de constantes de depuración que usamos. 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
Desde hace algún tiempo he estado utilizando un sitio de macros adoptado de varias anteriores. El mío se enfoca en el registro en la Consola, con énfasis en la verbosidad controlada y filtrada ; Si no te importa un montón de líneas de registro pero quieres activar y desactivar fácilmente lotes de ellos, entonces puedes encontrar esto útil.
Primero, sustituyo opcionalmente NSLog con printf como se describe en @Rodrigo arriba
#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, enciendo o apago el inicio de sesión.
#ifdef DEBUG
#define LOG_CATEGORY_DETAIL// comment out to turn all conditional logging off while keeping other DEBUG features
#endif
En el bloque principal, defina varias categorías correspondientes a los módulos en su aplicación. También defina un nivel de registro por encima del cual no se llamarán las llamadas de registro. Luego define varios sabores de salida de 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, con la configuración actual para kLOGIFcategory y kLOGIFdetailLTEQ, una llamada como
myLogLine(kLogVC, 2, @"%@",self);
se imprimirá pero esto no
myLogLine(kLogGCD, 2, @"%@",self);//GCD not being printed
ni lo hará
myLogLine(kLogGCD, 12, @"%@",self);//level too high
Si desea anular la configuración de una llamada de registro individual, use un nivel negativo:
myLogLine(kLogGCD, -2, @"%@",self);//now printed even tho'' GCD category not active.
Encuentro que los pocos caracteres adicionales de escribir cada línea valen como puedo
- Activa o desactiva una categoría completa de comentarios (por ejemplo, solo informa las llamadas marcadas como Modelo)
- informe sobre detalles finos con números de nivel superior o solo las llamadas más importantes marcadas con números más bajos
Estoy seguro de que muchos encontrarán que esto es un poco excesivo, pero en caso de que alguien encuentre que se adapte a sus propósitos ...
Deshabilitando todos los NSLogs, para alguien alérgico a MACROS, aquí hay algo que puedes compilar también:
void SJLog(NSString *format,...)
{
if(LOG)
{
va_list args;
va_start(args,format);
NSLogv(format, args);
va_end(args);
}
}
Y, utilízalo casi como NSLog:
SJLog(@"bye bye NSLogs !");
De este blog: http://whackylabs.com/rants/?p=134
Es fácil cambiar sus NSLogs existentes para mostrar el número de línea y la clase desde la que se llaman. Agregue una línea de código a su archivo de prefijo:
#define NSLog(__FORMAT__, ...) NSLog((@"%s [Line %d] " __FORMAT__), __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__)
Hay un nuevo truco que no da respuesta. Puedes usar printf
lugar de NSLog
. Esto le dará un registro limpio:
Con NSLog
obtienes cosas como esta:
2011-11-03 13:43:55.632 myApp[3739:207] Hello Word
Pero con printf
obtienes solo:
Hello World
Usa este codigo
#ifdef DEBUG
#define NSLog(FORMAT, ...) fprintf(stderr,"%s/n", [[NSString stringWithFormat:FORMAT, ##__VA_ARGS__] UTF8String]);
#else
#define NSLog(...) {}
#endif
Mi respuesta a esta pregunta podría ayudar, parece que es similar a la que Diederik cocinó. También es posible que desee reemplazar la llamada a 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 error / advertencia / error, enviar mensajes a un archivo o base de datos, así como a consola, o casi cualquier otra cosa que se pueda imaginar.
#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
Nueva incorporación a DLog. En lugar de eliminar totalmente la depuración de la aplicación lanzada, solo deshabilítela. Cuando el usuario tiene problemas, lo que requeriría la depuración, simplemente diga cómo habilitar la depuración en la aplicación publicada y solicitar los datos de registro por correo electrónico.
Versión corta: cree una variable global (sí, solución perezosa y simple) y modifique el DLog de esta manera:
BOOL myDebugEnabled = FALSE;
#define DLog(fmt, ...) if (myDebugEnabled) NSLog((@"%s [Line %d] " fmt), __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__);
Respuesta más larga en Jomnius iLessons iLearned: Cómo hacer el registro dinámico de depuración en la aplicación lanzada
Para complementar las respuestas anteriores, puede ser muy útil usar un reemplazo para NSLog en ciertas situaciones, especialmente al depurar. Por ejemplo, deshacerse de toda la información de fecha y nombre de proceso / id en cada línea puede hacer que la salida sea más legible y más rápida de iniciar.
El siguiente enlace proporciona un poco de munición útil para hacer que el registro simple sea mucho más agradable.
Sobre la base de las respuestas anteriores, aquí está lo que plagié y se me ocurrió. También se agrega 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
Tomé DLog
y ALog
de arriba, y agregué ULog
que genera un mensaje UIAlertView
.
Para resumir:
-
DLog
emitirá comoNSLog
solo cuando la variable DEBUG esté configurada -
ALog
siempre saldrá comoNSLog
-
ULog
mostrará elUIAlertView
solo cuando la variable DEBUG esté configurada
#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:
+1 Diederik
Es simple, por ejemplo.
- (void) applicationWillEnterForeground: (UIApplication *) application {
NSLog(@"%s", __PRETTY_FUNCTION__);
}
Salida: - [AppDelegate applicationWillEnterForeground:]
NSLog(@"%s %d %s %s", __FILE__, __LINE__, __PRETTY_FUNCTION__, __FUNCTION__);
Muestra el nombre del archivo, el número de línea y el nombre de la función:
/proj/cocoa/cdcli/cdcli.m 121 managedObjectContext managedObjectContext
__FUNCTION__
en C ++ muestra un nombre mutilado __PRETTY_FUNCTION__
muestra un bonito nombre de función, en cacao se ven iguales.
No estoy seguro de cuál es la forma correcta de deshabilitar NSLog, lo hice:
#define NSLog
Y no apareció ninguna salida de registro, sin embargo, no sé si esto tiene algún efecto secundario.