it-swarm.com.de

Wie kann ich den Methodennamen und die Zeilennummer ausdrucken und NSLog bedingt deaktivieren?

Ich halte eine Präsentation zum Debuggen in Xcode und möchte weitere Informationen zur effizienten Verwendung von NSLog erhalten.

Insbesondere habe ich zwei Fragen:

  • gibt es eine Möglichkeit, den Namen/die Zeilennummer der aktuellen Methode einfach mit NSLog zu erfassen?
  • gibt es eine Möglichkeit, alle NSLogs einfach zu "deaktivieren", bevor der Release-Code kompiliert wird?
444
rein

Hier sind einige nützliche Makros rund um NSLog, die ich häufig verwende:

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

Das DLog-Makro wird nur zur Ausgabe verwendet, wenn die DEBUG-Variable gesetzt ist (-DDEBUG in den C-Flags des Projekts für die Debug-Konfiguration).

ALog gibt immer Text aus (wie das normale NSLog).

Die Ausgabe (z. B. ALog (@ "Hello world")) sieht folgendermaßen aus:

-[LibraryController awakeFromNib] [Line 364] Hello world
591
diederikh

Ich habe DLog und ALog von oben genommen und ULog hinzugefügt, wodurch eine UIAlertView Nachricht ausgelöst wird.

Zusammenfassen:

  • DLog wird nur dann wie NSLog ausgegeben, wenn die Variable DEBUG gesetzt ist
  • ALog wird immer wie NSLog ausgegeben
  • ULog zeigt das UIAlertView nur an, wenn die Variable DEBUG gesetzt ist
 # ifdef DEBUG 
 # definiere DLog (fmt, ...) NSLog ((@ "% s [Line% d]" fmt), __PRETTY_FUNCTION__, __LINE__, ## __ VA_ARGS __); 
 # else 
 # definiere DLog (...) 
 # endif 
 # definiere 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 [Zeile% d]", __PRETTY_FUNCTION__, __LINE__] Nachricht: [NSString stringWithFormat: fmt, ## __ VA_ARGS__] Delegat: nil cancelButtonTitle: @ "Ok" otherButtonTitles: nil]; [alert show]; } 
 # else 
 # definiere ULog (...) 
 # endif 

So sieht es aus:

Debug UIAlertView

+1 Diederik

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

Gibt den Dateinamen, die Zeilennummer und den Funktionsnamen aus:

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

__FUNCTION__ in C++ zeigt verstümmelten Namen __PRETTY_FUNCTION__ zeigt Nice Funktionsname, in Kakao sehen sie gleich aus.

Ich bin mir nicht sicher, wie NSLog ordnungsgemäß deaktiviert werden kann.

#define NSLog

Es wurde keine Protokollausgabe angezeigt, ich weiß jedoch nicht, ob dies irgendwelche Nebenwirkungen hat.

74
stefanB

Hier eine große Sammlung von Debug-Konstanten, die wir verwenden. Genießen.

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

Es gibt einen neuen Trick, den man nicht beantworten kann. Sie können printf anstelle von NSLog verwenden. Dies gibt Ihnen ein sauberes Protokoll:

Mit NSLog erhalten Sie Folgendes:

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

Aber mit printf bekommen Sie nur:

Hello World

Verwenden Sie diesen Code

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

Meine Antwort auf diese Frage könnte helfen, sieht aus wie die, die Diederik sich ausgedacht hat. Möglicherweise möchten Sie auch den Aufruf von NSLog() durch eine statische Instanz Ihrer eigenen benutzerdefinierten Protokollierungsklasse ersetzen. Auf diese Weise können Sie ein Prioritätsflag für Debug-/Warn-/Fehlermeldungen hinzufügen und Nachrichten an eine Datei oder Datenbank senden genauso wie die Konsole oder so ziemlich alles, was man sich sonst noch vorstellen kann.

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

Wenn Sie alle NSLogs deaktivieren, können Sie auch Folgendes kompilieren:

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

Und benutze es fast wie NSLog:

SJLog(@"bye bye NSLogs !");

Von diesem Blog: http://whackylabs.com/rants/?p=134

13
chunkyguy

Um die obigen Antworten zu ergänzen, kann es in bestimmten Situationen, insbesondere beim Debuggen, sehr nützlich sein, einen Ersatz für NSLog zu verwenden. Wenn Sie beispielsweise alle Informationen zu Datum und Prozessname/ID in jeder Zeile löschen, wird die Ausgabe lesbarer und lässt sich schneller starten.

Der folgende Link bietet eine Menge nützlicher Munition, um die einfache Protokollierung viel angenehmer zu gestalten.

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

11
Quinn Taylor

Es ist einfach, Ihre vorhandenen NSLogs so zu ändern, dass Zeilennummer und Klasse angezeigt werden, von der aus sie aufgerufen werden. Fügen Sie Ihrer Präfixdatei eine Codezeile hinzu:

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

Es ist einfach, zum Beispiel

void) applicationWillEnterForeground: (UIApplication *) application {

    NSLog(@"%s", __PRETTY_FUNCTION__);

}

--- (Ausgabe: - [AppDelegate applicationWillEnterForeground:]

7
Venkat Reddy

aufbauend auf den obigen Antworten habe ich Folgendes plagiiert und erfunden. Es wurde auch eine Speicherprotokollierung hinzugefügt.

#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
5
Dickey Singh

Neu bei DLog. Anstatt das Debugging vollständig aus der freigegebenen Anwendung zu entfernen, deaktivieren Sie es nur. Wenn der Benutzer Probleme hat, die ein Debuggen erfordern würden, sagen Sie einfach, wie Debuggen in freigegebener Anwendung aktivieren und fordern Sie Protokolldaten per E-Mail an.

Kurzversion: Globale Variable erstellen (ja, faule und einfache Lösung) und DLog wie folgt ändern:

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

Längere Antwort bei Jomnius iLessons iLearned: So führen Sie die dynamische Debug-Protokollierung in einer freigegebenen Anwendung durch

4
JOM

Seit einiger Zeit verwende ich eine Seite mit Makros, die von mehreren oben übernommen wurden. Mein Fokus liegt auf der Protokollierung in der Konsole, mit dem Schwerpunkt auf kontrollierte und gefilterte Ausführlichkeit; Wenn Ihnen viele Protokollzeilen nichts ausmachen, Sie aber Stapel von Protokollzeilen einfach ein- und ausschalten möchten, ist dies möglicherweise hilfreich.

Zuerst ersetze ich optional NSLog durch printf, wie oben von @Rodrigo beschrieben

#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

Als nächstes schalte ich die Protokollierung ein oder aus.

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

Definieren Sie im Hauptblock verschiedene Kategorien, die den Modulen in Ihrer App entsprechen. Definieren Sie auch eine Protokollierungsstufe level, über der keine Protokollierungsanrufe aufgerufen werden. Definieren Sie dann verschiedene Flavours der NSLog-Ausgabe

#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

Somit ist mit den aktuellen Einstellungen für kLOGIFcategory und kLOGIFdetailLTEQ ein Aufruf wie

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

wird gedruckt, aber das wird nicht

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

noch wird

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

Wenn Sie die Einstellungen für einen einzelnen Protokollaufruf überschreiben möchten, verwenden Sie eine negative Stufe:

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

Ich finde, dass die wenigen zusätzlichen Zeichen für die Eingabe jeder Zeile so viel wert sind, wie ich kann

  1. Ein- oder Ausschalten einer gesamten Kommentarkategorie (z. B. nur die mit Modell gekennzeichneten Anrufe melden)
  2. detailgenauigkeit mit höheren Nummern oder nur die wichtigsten Anrufe mit niedrigeren Nummern

Ich bin sicher, viele werden das als Overkill empfinden, aber nur für den Fall, dass jemand es für ihre Zwecke findet.

3
cate