Yöntem adı ve satır numarası nasıl yazdırılır ve NSLog koşullu olarak devre dışı bırakılır?


446

Xcode hata ayıklama hakkında bir sunum yapıyorum ve NSLog verimli kullanma hakkında daha fazla bilgi almak istiyorum.

Özellikle, iki sorum var:

  • kolayca mevcut yöntemin adı / satır numarasını NSLog için bir yolu var mı?
  • kodunu derlemeden önce tüm NSLogs'u kolayca "devre dışı bırakmanın" bir yolu var mı?

12
Sık kullanılanların (yıldız) daha fazla oy verildiği ilk soru ... +1 ..
Fahim Parkar

Yanıtlar:


592

İşte NSLog etrafında bazı yararlı makrolar çok kullanıyorum:

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

DLog makrosu yalnızca DEBUG değişkeni ayarlandığında (hata ayıklama onayı için projelerin C bayraklarında -DDEBUG) çıktı almak için kullanılır.

ALog her zaman metin gönderir (normal NSLog gibi).

Çıktı (örneğin ALog (@ "Merhaba dünya")) şöyle görünecektir:

-[LibraryController awakeFromNib] [Line 364] Hello world

Neden bir ## var? Bunun argümanları birbirine yapıştırmak olduğunu düşündüm, ama sen hiçbir şeye yapışmıyorsun.
Casebash

1
Bu, argümanların olası makro genişlemesini önler
Dieerikh

Bu genel olarak makrolarda olabilir; bazı makrolar birden fazla satır verir. Her zaman parantez kullanmak için başka bir argüman ;-).
Aralık'ta öldü

great ve cocos2d api benzer günlük ifadesine sahiptir.
Yoon Lee

Kontrol dizesine eklenmesine nasıl (@"%s [Line %d] " fmt)neden olur fmt? Bu sözdizimini bu hata ayıklama makrosu dışında görmedim.
Robert Altman

141

Ben aldım DLogve ALogyukarıdan ve eklenen ULogbir yükseltir hangi UIAlertViewmesajı.

Özetlemek:

  • DLogNSLogyalnızca DEBUG değişkeni ayarlandığında olduğu gibi çıkar
  • ALog her zaman çıktı gibi NSLog
  • ULoggösterecektir UIAlertViewDEBUG değişken kümesidir yalnızca
#ifdef DEBUG
# tanım DLog (fmt, ...) NSLog ((@ @%% [[% d] "fmt), __PRETTY_FUNCTION__, __LINE__, ## __ VA_ARGS__);
#Başka
# DLog tanımla (...)
#endif
#define ALog (fmt, ...) NSLog ((@ @%% [[% d] "fmt), __PRETTY_FUNCTION__, __LINE__, ## __ VA_ARGS__);
#ifdef DEBUG
# define ULog (fmt, ...) {UIAlertView * alert = [[UIAlertView ayır] initWithTitle: [NSString stringWithFormat: @ "% s \ n [Satır% d]", __PRETTY_FUNCTION__, __LINE__] mesajı: [NSString stringWithFormat: fmt , ## __ VA_ARGS__] temsilci: nil cancelButtonTitle: @ "Ok" otherButtonTitles: nil]; [uyarı gösterisi]; }
#Başka
# tanım ULog (...)
#endif

Öyle görünüyor:

Hata ayıklama UIAlertView

+1 Diederik


ALog + DLog kodumu da ULog ile genişleteceğim. Çok kullanışlı.
neoneye

Bu kod,
DEBUG'da

#Define yönergelerinin bazıları neden noktalı virgülle bitiyor?
Monstieur

@Locutus Yani ifadeden sonra noktalı virgül koymak zorunda değilsiniz DLog. Bu yararlıdır, çünkü sürüm derlemelerinde DLoghiçbir şeye derlenmezseniz ve kodunuzda sarkan bir noktalı virgül bırakılır. Bu bir hata değildir, ancak başka bir noktalı virgül izliyorsa ayarlarınıza bağlı olarak bir uyarı verebilir.
Zev Eisenberg

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

Dosya adı, satır numarası ve işlev adı çıktısı verir:

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

__FUNCTION__C ++ ile karışık adı __PRETTY_FUNCTION__güzel fonksiyon adını gösterir, kakao aynı görünüyor.

NSLog'u devre dışı bırakmanın uygun yolunun ne olduğundan emin değilim, yaptım:

#define NSLog

Ve hiçbir günlük çıkışı ortaya çıkmadı, ancak bunun herhangi bir yan etkisi olup olmadığını bilmiyorum.


20

Burada kullandığımız büyük bir hata ayıklama sabit koleksiyonu. Zevk almak.

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

Cevap vermeyen yeni bir numara var. Bunun printfyerine kullanabilirsiniz NSLog. Bu size temiz bir günlük verecektir:

Sizinle NSLogböyle şeyler olsun:

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

Ama printfsadece seninle olsun:

Hello World

Bu kodu kullan

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

16

Bu soruya cevabım yardımcı olabilir, sanki Diederik'in pişirdiği gibi. Ayrıca, çağrıyı NSLog()kendi özel günlük sınıfınızın statik bir örneğiyle değiştirmek isteyebilirsiniz , böylece hata ayıklama / uyarı / hata iletileri için öncelik bayrağı ekleyebilir, konsolun yanı sıra bir dosyaya veya veritabanına ileti gönderebilir veya aklınıza gelebilecek başka ne varsa.

#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

Çünkü %sApple'ın kullanımdan kaldırmaya çalıştığı format belirleyiciden -Wcstring-format-directivekaçtınız ve 2015'te yeni tanıtılan Clang uyarısından kaçındınız.
Jeff


11

Yukarıdaki cevapları tamamlamak için, belirli durumlarda, özellikle hata ayıklama sırasında NSLog için bir yedek kullanmak oldukça yararlı olabilir. Örneğin, her satırdaki tüm tarih ve işlem adı / kimlik bilgisinden kurtulmak, çıktıyı daha okunabilir ve önyükleme işlemini daha hızlı hale getirebilir.

Aşağıdaki bağlantı basit günlüğü çok daha güzel hale getirmek için oldukça kullanışlı bir cephane sağlar.

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


11

Mevcut NSLogs'unuzu, çağrıldıkları satır numarasını ve sınıfı gösterecek şekilde değiştirmek kolaydır. Ön ek dosyanıza bir kod satırı ekleyin:

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

3
Bu harika! bunu nasıl çabuk yapardın?
uplearnedu.com

@AddisDev Bunu en çok beğendim. Çok temiz ve basit. Yalnızca NSLog kullanıyorum. DLog ve ULog'un zaten ne olduğu hakkında hiçbir fikrim yok! Teşekkürler.
Oylandı

@AddisDev Apple'ın neden bu kadar önemli verileri varsayılan olarak NSLog () öğesine eklemediğini gerçekten anlamıyorum? Tuhaf...
Charles Robertson

8

Çok basit, örneğin

- (geçersiz) applicationWillEnterForeground: (UIApplication *) application {

    NSLog(@"%s", __PRETTY_FUNCTION__);

}

Çıktı: - [AppDelegate uygulamasıWillEnterForeground:]


5

Yukarıdaki cevapların üzerine inşa ederek, intihal ettiğim ve bulduğum şey bu. Ayrıca bellek günlüğü eklendi.

#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

DLog'a yeni bir ek. Hata ayıklamayı serbest bırakılan uygulamadan tamamen kaldırmak yerine, yalnızca devre dışı bırakın. Kullanıcıda hata ayıklama gerektiren sorunlar olduğunda, serbest bırakılan uygulamada hata ayıklamanın nasıl etkinleştirileceğini söyleyin ve günlük verilerini e-posta yoluyla isteyin.

Kısa versiyon: global değişken oluşturun (evet, tembel ve basit bir çözüm) ve DLog'u şu şekilde değiştirin:

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

Jomnius iLessons iLearned'de daha uzun cevap: Yayımlanan Uygulamada Dinamik Hata Ayıklama Günlüğü Nasıl Yapılır?


3

Bir süredir yukarıdakilerin çoğundan benimsenen bir makro sitesi kullanıyorum. Mayın, kontrollü ve filtrelenmiş ayrıntılara vurgu yaparak Konsolda oturum açmaya odaklanıyor ; Çok fazla günlük satırı sakıncası yoksa ancak gruplarını kolayca açmak ve kapatmak istiyorsanız, bunu yararlı bulabilirsiniz.

İlk olarak, isteğe bağlı olarak yukarıda @Rodrigo tarafından açıklandığı gibi NSLog'u printf ile değiştiriyorum

#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

Ardından, günlüğe kaydetmeyi açıp kapatıyorum.

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

Ana blokta, uygulamanızdaki modüllere karşılık gelen çeşitli kategoriler tanımlayın . Ayrıca, üzerinde günlük aramalarının çağrılmayacağı bir günlük seviyesi de tanımlayın . Ardından NSLog çıktısının çeşitli lezzetlerini tanımlayın

#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

Bu nedenle, kLOGIFcategory ve kLOGIFdetailLTEQ için geçerli ayarlarla,

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

yazdırılacak, ancak bu yazdırılmayacak

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

ne olmayacak

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

Tek bir günlük çağrısının ayarlarını geçersiz kılmak istiyorsanız, negatif bir düzey kullanın:

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

Her satırı yazmanın fazladan birkaç karakterini değerli buluyorum

  1. Bir yorum kategorisinin tamamını açma veya kapatma (örneğin, yalnızca Model olarak işaretlenmiş çağrıları bildirin)
  2. daha yüksek seviyeli numaralarla veya yalnızca daha düşük rakamlarla işaretlenmiş en önemli çağrılarla ilgili ince ayrıntıları rapor edin

Eminim birçoğu bunu biraz aşırıya kaçacaktır, ama birinin amacına uygun bulması durumunda ..

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.