Como imprimir o nome do método e o número da linha e desabilitar condicionalmente o NSLog?

Estou fazendo uma apresentação sobre debugging no Xcode e gostaria de obter mais informações sobre o uso eficiente do NSLog.

Em particular, tenho duas perguntas:

  • Existe uma maneira de facilmente NSLog o nome / número da linha do método atual?
  • Existe uma maneira de “desativar” todos os NSLogs facilmente antes de compilar para o código de lançamento?

Aqui estão algumas macros úteis em torno do NSLog que uso muito:

#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__) 

A macro DLog é usada para saída somente quando a variável DEBUG é definida (-DDEBUG nas sinalizações C dos projetos para a confirmação de debugging).

ALog sempre emitirá texto (como o NSLog normal).

A saída (por exemplo, ALog (@ “Hello world”)) ficará assim:

 -[LibraryController awakeFromNib] [Line 364] Hello world 

Eu tirei DLog e ALog de cima, e adicionei o ULog que gera uma mensagem UIAlertView .

Para resumir:

  • DLog irá produzir como NSLog apenas quando a variável DEBUG está definida
  • ALog irá sempre produzir como NSLog
  • ULog mostrará o UIAlertView somente quando a variável DEBUG estiver configurada
 #ifdef DEBUG
 # define DLog (fmt, ...) NSLog ((@ "% s [Linha% d]" fmt), __PRETTY_FUNCTION__, __LINE__, ## __ VA_ARGS__);
 #outro
 # define DLog (...)
 #fim se
 #define ALog (fmt, ...) NSLog ((@ "% s [Linha% d]" fmt), __PRETTY_FUNCTION__, __LINE__, ## __ VA_ARGS__);
 #ifdef DEBUG
 # define ULog (fmt, ...) {alerta UIAlertView * = [[UIAlertView alloc] initWithTitle: [string NSStringWithFormat: @ "% s \ n [linha% d]", mensagem __PRETTY_FUNCTION__, __LINE__]: [NSString stringWithFormat: fmt , ## __ VA_ARGS__] delegate: nil cancelButtonTitle: @ "Ok" otherButtonTitles: nil];  [show de alerta];  }
 #outro
 # define ULog (...)
 #fim se

Isto é o que parece:

Depurar UIAlertView

+1 Diederik

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

Saídas nome do arquivo, número da linha e nome da function:

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

__FUNCTION__ em C ++ mostra o nome __PRETTY_FUNCTION__ mostra o nome da function legal, no cacau eles são parecidos.

Não tenho certeza qual é a maneira correta de desabilitar o NSLog, eu fiz:

 #define NSLog 

E nenhuma saída de registro apareceu, no entanto, não sei se isso tem algum efeito colateral.

Aqui está uma grande coleção de constantes de debugging que usamos. Apreciar.

 // 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 

Há um novo truque que nenhuma resposta dá. Você pode usar printf vez de NSLog . Isso lhe dará um log limpo:

Com o NSLog você obtém coisas assim:

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

Mas com printf você só recebe:

 Hello World 

Use este código

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

Minha resposta a esta pergunta pode ajudar, parece que é semelhante à que Diederik criou. Você também pode querer replace a chamada para NSLog() por uma instância estática de sua própria class de log personalizada, dessa forma você pode adicionar um sinalizador de prioridade para mensagens de debugging / aviso / erro, enviar mensagens para um arquivo ou database, bem como console, ou praticamente tudo o que você pode pensar.

 #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 

Desativando todos os NSLogs, para alguém alérgico a MACROS, aqui está algo que você pode compilar também:

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

E, use quase como NSLog:

 SJLog(@"bye bye NSLogs !"); 

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

Para complementar as respostas acima, pode ser bastante útil usar um substituto para o NSLog em determinadas situações, especialmente durante a debugging. Por exemplo, livrar-se de todas as informações de data e nome / identificação do processo em cada linha pode tornar a saída mais legível e mais rápida de inicializar.

O seguinte link fornece um pouco de munição útil para tornar o registro simples muito mais agradável.

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

É fácil alterar os NSLogs existentes para exibir o número da linha e a class da qual eles são chamados. Adicione uma linha de código ao seu arquivo de prefixo:

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

É simples, por exemplo

– (void) applicationWillEnterForeground: aplicação (UIApplication *) {

  NSLog(@"%s", __PRETTY_FUNCTION__); 

}

Saída: – [AppDelegate applicationWillEnterForeground:]

Construindo em cima de respostas acima, aqui está o que eu plagiei e inventei. Também adicionado log de memory.

 #import  #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 

Nova adição ao DLog. Em vez de remover totalmente o debug do aplicativo liberado, desative-o. Quando o usuário tiver problemas, o que exigiria debugging, informe como ativar a debugging no aplicativo liberado e solicitar dados de log por email.

Versão resumida: crie uma variável global (sim, solução simples e preguiçosa) e modifique o DLog assim:

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

Resposta mais longa no Jomnius iLessons iLearned: Como fazer o registro dynamic de debugging no aplicativo liberado

Há algum tempo venho usando um site de macros adotado de vários acima. O meu foco em fazer o login no console, com ênfase na verbosidade controlada e filtrada ; Se você não se importar com muitas linhas de log, mas quiser alternar facilmente lotes delas on e off, então você pode achar isso útil.

Primeiro, eu opcionalmente substituo o NSLog por printf como descrito por @Rodrigo acima

 #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 

Em seguida, eu alterno o log on ou off.

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

No bloco principal, defina várias categorias correspondentes aos módulos no seu aplicativo. Defina também um nível de registro acima do qual as chamadas de registro não serão chamadas. Em seguida, defina vários sabores de saída 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 

Assim, com as configurações atuais para kLOGIFcategory e kLOGIFdetailLTEQ, uma chamada como

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

vai imprimir, mas isso não vai

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

nem vai

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

Se você quiser replace as configurações de uma chamada de registro individual, use um nível negativo:

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

Eu acho que os poucos caracteres extras de digitação de cada linha valem como eu posso

  1. Ativar ou desativar toda uma categoria de comentário (por exemplo, reportar somente as chamadas marcadas como Modelo)
  2. relatar detalhes finos com números de nível superior ou apenas as chamadas mais importantes marcadas com números mais baixos

Tenho certeza que muitos acharão isso um pouco exagerado, mas apenas no caso de alguém achar que é adequado aos seus propósitos.