Come stampare il nome del metodo e il numero di riga e disabilitare condizionalmente NSLog?


446

Sto facendo una presentazione sul debug in Xcode e vorrei ottenere maggiori informazioni sull'uso efficiente di NSLog.

In particolare, ho due domande:

  • c'è un modo per NSLog facilmente il nome / numero di riga del metodo corrente?
  • c'è un modo per "disabilitare" facilmente tutti i NSLog prima di compilare il codice di rilascio?

12
prima domanda in cui i preferiti (stella) sono più di voti positivi ... +1 ..
Fahim Parkar

Risposte:


592

Ecco alcune macro utili intorno a 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 configurazione di debug).

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

L'output (ad es. ALog (@ "Hello world")) sarà simile al seguente:

-[LibraryController awakeFromNib] [Line 364] Hello world

Perché hai un ##? Ho pensato che fosse per incollare argomenti insieme, ma non stai incollando nulla.
Casebash,

1
Ciò impedisce la possibile espansione macro degli argomenti
diederikh

Ciò può accadere con le macro in generale; alcune macro producono più righe. Solo un altro argomento per usare sempre le parentesi graffe ;-).
diederikh

great e cocos2d api ha l'istruzione log simile.
Yoon Lee,

In che modo (@"%s [Line %d] " fmt)provoca l' fmtaggiunta alla stringa di controllo? Non ho visto questa sintassi diversa da questa macro di debug.
Robert Altman,

141

Ho preso DLoge ALogdall'alto, e ho aggiunto ULogche solleva un UIAlertViewmessaggio.

Riassumere:

  • DLogverrà emesso come NSLogsolo quando è impostata la variabile DEBUG
  • ALog uscirà sempre come NSLog
  • ULogmostrerà il UIAlertViewsolo quando è impostata la variabile DEBUG
#ifdef DEBUG
# define DLog (fmt, ...) NSLog ((@ "% s [Line% d]" fmt), __PRETTY_FUNCTION__, __LINE__, ## __ VA_ARGS__);
#altro
# define DLog (...)
#finisci se
#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__] messaggio: [NSString stringWithFormat: fmt , ## __ VA_ARGS__] delegato: nil cancelButtonTitle: @ "Ok" otherButtonTitles: nil]; [avviso]; }
#altro
# define ULog (...)
#finisci se

Ecco come appare:

Debug UIAlertView

+1 Diederik


Estenderò anche il mio codice ALog + DLog con ULog. Molto utile.
Neoneye,

Questo codice provoca un errore variabile non utilizzato in Xcode 5.1 se non in esecuzione in DEBUG :(
yonix

Perché alcune delle direttive #define terminano con un punto e virgola?
Monstieur,

@Locutus Quindi non è necessario inserire un punto e virgola dopo la DLogdichiarazione. Questo è utile perché se lo facessi, nelle build di rilascio, non verrai DLogcompilato nel nulla e verrai lasciato con un punto e virgola nel tuo codice. Questo non è un errore, ma potrebbe generare un avviso, a seconda delle impostazioni, se segue un altro punto e virgola.
Zev Eisenberg,

74
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 alterato __PRETTY_FUNCTION__mostra un bel nome di funzione, nel cacao sembrano uguali.

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

#define NSLog

E non è stato visualizzato alcun output di registrazione, tuttavia non so se questo abbia effetti collaterali.


20

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

19

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

Con NSLogte ottieni cose come questa:

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

Ma con printfte ottieni 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

16

La mia risposta a questa domanda di aiuto forza, sembra che sia simile a quello Diederik cucinato. È inoltre possibile sostituire la chiamata NSLog()con un'istanza statica della propria classe di registrazione personalizzata, in questo modo è possibile aggiungere un flag di priorità per i messaggi di debug / avviso / errore, inviare messaggi a un file o database nonché alla console, oppure 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

Perché hai %sevitato l' -Wcstring-format-directiveidentificatore di formato che Apple sta cercando di deprecare ed evitato l' avvertimento di Clang recentemente introdotto nel 2015.
Jeff


11

Per integrare le risposte di cui sopra, può essere molto utile utilizzare un sostituto di NSLog in determinate situazioni, specialmente durante il debug. Ad esempio, sbarazzarsi di tutte le informazioni relative a data e nome processo / ID su ciascuna riga può rendere l'output più leggibile e più veloce da avviare.

Il seguente link fornisce molte munizioni utili per rendere la registrazione semplice molto più piacevole.

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


11

È facile cambiare i tuoi NSLogs esistenti per visualizzare il numero di riga e la classe 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__)

3
Questo è fantastico! come faresti in fretta?
uplearnedu.com il

@AddisDev Mi piace di più. Molto pulito e semplice. Uso solo NSLog. Non ho idea di cosa siano DLog e ULog! Grazie. Voto votato ...
Charles Robertson,

@AddisDev Davvero non capisco perché Apple non aggiunga questi dati di vitale importanza a NSLog () per impostazione predefinita? Bizzarro ...
Charles Robertson,

8

È semplice, per esempio

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

    NSLog(@"%s", __PRETTY_FUNCTION__);

}

Output: - [AppDelegate applicationWillEnterForeground:]


5

basandomi sulle risposte di cui sopra, ecco cosa ho plagiato e trovato. Aggiunta anche la registrazione della 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

4

Nuova aggiunta a DLog. Invece di rimuovere totalmente il debug dall'applicazione rilasciata, disabilitalo solo. Quando l'utente ha problemi, che richiederebbero il debug, basta dire come abilitare il debug nell'applicazione rilasciata e richiedere i dati del registro via e-mail.

Versione breve: crea una variabile globale (sì, soluzione pigra e semplice) e modifica 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 su iLessons di Jomnius iLearned: come eseguire la registrazione dinamica del debug nell'applicazione rilasciata


3

Da qualche tempo utilizzo un sito di macro adottato da diversi sopra. Il mio focus sulla registrazione nella Console, con l'accento sulla verbosità controllata e filtrata ; se non ti dispiace un sacco di linee di log ma vuoi accenderle e spegnerle facilmente, potresti trovare questo utile.

Innanzitutto, opzionalmente sostituisco NSLog con printf come descritto da @Rodrigo sopra

#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, accendo o spengo la registrazione.

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

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

Pertanto, con le impostazioni correnti per kLOGIFcategory e kLOGIFdetailLTEQ, una chiamata simile

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

stamperà ma questo non lo farà

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

né lo farà

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 extra della digitazione di ogni riga valgano quanto posso allora

  1. Attiva o disattiva un'intera categoria di commenti (ad esempio segnala solo quelle chiamate contrassegnate come modello)
  2. riferire in dettaglio con numeri di livello superiore o solo le chiamate più importanti contrassegnate con numeri più bassi

Sono sicuro che molti lo troveranno un po 'eccessivo, ma nel caso in cui qualcuno lo ritenga adatto ai loro scopi ...

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.