Come stampare il nome del metodo e il numero di riga e disabilitare NSLog in modo condizionale?

Sto facendo una presentazione sul debugging in Xcode e vorrei avere maggiori informazioni sull’utilizzo efficiente di NSLog.

In particolare, ho due domande:

  • c’è un modo per NSLog facilmente il nome / numero di linea del metodo corrente?
  • c’è un modo per “disabilitare” tutti NSLogs facilmente prima della compilazione per il codice di rilascio?

Ecco alcune macro utili su NSLog che uso molto:

#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 viene utilizzata per l’output solo quando è impostata la variabile DEBUG (-DDEBUG nei flag C del progetto per la confugurazione del debug).

ALog genererà sempre il testo (come il normale NSLog).

L’output (ad esempio ALog (@ “Hello world”)) sarà simile a questo:

 -[LibraryController awakeFromNib] [Line 364] Hello world 

Ho preso DLog e DLog dall’alto e ULog aggiunto ULog che genera un messaggio UIAlertView .

Riassumere:

  • DLog verrà emesso come NSLog solo quando è impostata la variabile DEBUG
  • ALog uscirà sempre come NSLog
  • ULog mostrerà UIAlertView solo quando è impostata la variabile DEBUG
 #ifdef DEBUG
 # define DLog (fmt, ...) NSLog ((@ "% s [Riga% d]" fmt), __PRETTY_FUNCTION__, __LINE__, ## __ VA_ARGS__);
 #altro
 # define DLog (...)
 #finisci se
 #define ALog (fmt, ...) NSLog ((@ "% s [Riga% d]" fmt), __PRETTY_FUNCTION__, __LINE__, ## __ VA_ARGS__);
 #ifdef DEBUG
 # define ULog (fmt, ...) {UIAlertView * alert = [[UIAlertView alloc] initWithTitle: [NSString stringWithFormat: @ "% s \ n [Riga% d]", __PRETTY_FUNCTION__, __LINE__] messaggio: [NSString stringWithFormat: fmt , ## __ VA_ARGS__] delegate: nil cancelButtonTitle: @ "Ok" otherButtonTitles: nil];  [avviso spettacolo];  }
 #altro
 # define ULog (...)
 #finisci se

Questo è quello che sembra:

Debug UIAlertView

+1 Diederik

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

Emette il nome del file, il numero di riga e il nome della funzione:

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

__FUNCTION__ in C ++ mostra il nome __PRETTY_FUNCTION__ mostra il nome della funzione piacevole, nel cocoa hanno lo stesso aspetto.

Non sono sicuro di quale sia il modo corretto di disabilitare NSLog, l’ho fatto:

 #define NSLog 

E non è emerso alcun output di registrazione, tuttavia non so se questo ha effetti collaterali.

Ecco una grande raccolta di costanti di debug che usiamo. Godere.

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

C’è un nuovo trucco che nessuna risposta dà. Puoi usare printf invece NSLog . Questo ti darà un registro pulito:

Con NSLog ottieni cose come questa:

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

Ma con printf si ottiene solo:

 Hello World 

Usa questo codice

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

La mia risposta a questa domanda potrebbe aiutare, sembra che sia simile a quello di Diederik cucinato. Si potrebbe anche voler sostituire la chiamata a NSLog() con un’istanza statica della propria class di registrazione personalizzata, in questo modo è ansible aggiungere un flag di priorità per i messaggi di debug / warning / error, inviare messaggi a un file o database così come console, o praticamente qualsiasi altra cosa tu possa pensare.

 #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 

Disabilitando tutti gli NSlog, per qualcuno allergico a MACROS, ecco qualcosa che puoi compilare anche:

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

E, usalo quasi come NSLog:

 SJLog(@"bye bye NSLogs !"); 

Da questo blog: http://whackylabs.com/rants/?p=134

Per completare le risposte sopra, può essere abbastanza utile utilizzare un sostituto di NSLog in determinate situazioni, specialmente quando si esegue il debug. Ad esempio, eliminare tutte le informazioni sulla data e sul nome del processo / id su ogni riga può rendere l’output più leggibile e più veloce da avviare.

Il seguente link fornisce un bel po ‘di munizioni utili per rendere molto più semplice la registrazione.

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

È facile modificare i NSLogs esistenti per visualizzare il numero di riga e la class da cui vengono chiamati. Aggiungi una riga di codice al tuo file prefisso:

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

È semplice, per esempio

– (void) applicationWillEnterForeground: (applicazione UIApplication *) {

  NSLog(@"%s", __PRETTY_FUNCTION__); 

}

Uscita: – [AppDelegate applicationWillEnterForeground:]

basandosi sulle risposte di sopra, ecco cosa ho plagiato e inventato. Aggiunta anche la registrazione di memoria.

 #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 

Nuova aggiunta a DLog. Invece di rimuovere completamente il debug dall’applicazione rilasciata, disabilitarlo. Quando l’utente ha problemi, che richiederebbero il debug, è sufficiente indicare come abilitare il debug nell’applicazione rilasciata e richiedere i dati di log via e-mail.

Versione breve: creare una variabile globale (sì, soluzione pigra e semplice) e modificare DLog in questo modo:

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

Risposta più lunga a Jomnius iLessons iLearned: Come eseguire il debug dinamico nella registrazione dell’applicazione rilasciata

Da un po ‘di tempo utilizzo un sito di macro adottato da molti sopra. Il mio objective è quello di accedere alla console, con l’accento sulla verbosità controllata e filtrata ; se non ti dispiace un sacco di linee di log, ma vuoi passare facilmente a batch di esse on e off, allora potresti trovare utile.

Per prima cosa, opzionalmente sostituisco NSLog con printf come descritto sopra da @Rodrigo

 #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 

Successivamente, accedo o spengo il log.

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

Nel blocco principale, definisci varie categorie corrispondenti ai moduli nella tua app. Definire inoltre un livello di registrazione al di sopra del quale le chiamate di registrazione non verranno chiamate. Quindi definire i vari sapori dell’output di 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 

Quindi, con le impostazioni correnti per kLOGIFcategory e kLOGIFdetailLTEQ, una chiamata come

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

stamperà ma questo non lo farà

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

né volontà

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

Se si desidera sovrascrivere le impostazioni per una singola chiamata di registro, utilizzare un livello negativo:

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

Trovo che i pochi caratteri in più di digitare ogni riga valgano come posso allora

  1. Attiva o distriggers un’intera categoria di commenti (ad esempio, segnala solo le chiamate contrassegnate come Modello)
  2. riportare dettagli precisi con numeri di livello superiore o solo le chiamate più importanti contrassegnate con numeri più bassi

Sono sicuro che molti troveranno questo un po ‘eccessivo, ma nel caso qualcuno lo trovi adatto ai loro scopi ..