代码之家  ›  专栏  ›  技术社区  ›  rein

如何打印出方法名和行号,并有条件地禁用nslog?

  •  442
  • rein  · 技术社区  · 16 年前

    我正在Xcode中做一个关于调试的演示,希望获得有关有效使用nslog的更多信息。

    特别是,我有两个问题:

    • 有没有一种方法可以轻松地nslog当前方法的名称/行号?
    • 在编译发布代码之前,是否有一种方法可以轻松地“禁用”所有nslog?
    13 回复  |  直到 8 年前
        1
  •  587
  •   diederikh    12 年前

    下面是一些关于nslog的有用宏,我经常使用:

    #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宏仅用于在设置调试变量时输出(调试配置的项目C标志中有-ddebug)。

    ALOG将始终输出文本(如常规nslog)。

    输出(例如alog(@“Hello World”))如下:

    -[LibraryController awakeFromNib] [Line 364] Hello world
    
        2
  •  141
  •   Sujay DÅ©ng Nguyễn    10 年前

    我已经带走了 DLog ALog 从上面,并添加 ULog 提出一个 UIAlertView 消息。

    总结:

    • 德洛格 将输出为 NSLog 仅当设置了调试变量时
    • 课文 总是输出 国家统计局
    • 乌洛格 将展示 uiAlctVIEW 仅当设置了调试变量时
    #ifdef DEBUG
    #   define DLog(fmt, ...) NSLog((@"%s [Line %d] " fmt), __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__);
    #else
    #   define DLog(...)
    #endif
    #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__] message:[NSString stringWithFormat:fmt, ##__VA_ARGS__]  delegate:nil cancelButtonTitle:@"Ok" otherButtonTitles:nil]; [alert show]; }
    #else
    #   define ULog(...)
    #endif
    

    这就是它的样子:

    Debug UIAlertView

    + 1迪埃德里克

        3
  •  74
  •   Ben Clayton    13 年前
    NSLog(@"%s %d %s %s", __FILE__, __LINE__, __PRETTY_FUNCTION__, __FUNCTION__);
    

    输出文件名、行号和函数名:

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

    __FUNCTION__ 在C++中显示被损坏的名称 __PRETTY_FUNCTION__ 显示了很好的函数名,在cocoa中它们看起来是一样的。

    我不确定禁用nslog的正确方法是什么,我做到了:

    #define NSLog
    

    没有日志输出出现,但是我不知道这是否有任何副作用。

        4
  •  20
  •   SEQOY Development Team    15 年前

    这里有一个我们使用的调试常量的大集合。享受。

    // 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
    
        5
  •  19
  •   Rodrigo    13 年前

    有一个没有答案的新把戏。你可以使用 printf 相反 NSLog . 这将为您提供一个干净的日志:

    国家统计局 你得到这样的东西:

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

    但与 普林特 你只得到:

    Hello World
    

    使用此代码

    #ifdef DEBUG
        #define NSLog(FORMAT, ...) fprintf(stderr,"%s\n", [[NSString stringWithFormat:FORMAT, ##__VA_ARGS__] UTF8String]);
    #else
        #define NSLog(...) {}              
    #endif
    
        6
  •  16
  •   Community CDub    8 年前

    我的答案 this question 可能会有帮助,看起来就像迪德里克做的一样。您可能还需要将呼叫替换为 NSLog() 通过自定义日志类的静态实例,您可以为调试/警告/错误消息添加优先级标志,将消息发送到文件或数据库以及控制台,或者几乎任何您能想到的事情。

    #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
    
        7
  •  13
  •   Refactor    12 年前

    禁用所有nslog,对于对宏过敏的人,您也可以编译以下内容:

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

    而且,使用它就像nslog一样:

    SJLog(@"bye bye NSLogs !");
    

    从这个博客: http://whackylabs.com/rants/?p=134

        8
  •  11
  •   Quinn Taylor    16 年前

    为了补充以上的答案,在某些情况下,特别是在调试时,使用nslog替换可能非常有用。例如,去掉每一行上的所有日期和进程名/id信息可以使输出更可读、更快速地引导。

    下面的链接提供了大量有用的弹药,可以使简单的日志记录变得更好。

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

        9
  •  11
  •   AddisDev    12 年前

    可以很容易地将现有nslog更改为显示从中调用它们的行号和类。在前缀文件中添加一行代码:

    #define NSLog(__FORMAT__, ...) NSLog((@"%s [Line %d] " __FORMAT__), __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__)
    
        10
  •  6
  •   Venkat Reddy    10 年前

    例如,它很简单

    -(void)应用程序将进入前台:(uiapplication*)应用程序{

        NSLog(@"%s", __PRETTY_FUNCTION__);
    

    }

    输出: -[应用程序委派应用程序将进入前台:]

        11
  •  5
  •   Dickey Singh    12 年前

    在以上答案的基础上,下面是我剽窃并提出的问题。还添加了内存日志记录。

    #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
    
        12
  •  4
  •   JOM agenthunt    13 年前

    新添加到DLOG。不要完全从已发布的应用程序中删除调试,只需禁用它。当用户遇到需要调试的问题时,只需告诉如何 在已发布的应用程序中启用调试 并通过电子邮件请求日志数据。

    短版本:创建全局变量(是的,懒惰和简单的解决方案),然后这样修改dlog:

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

    在Jomnius Ilessons Ilearned,回答时间更长: How to Do Dynamic Debug Logging in Released Application

        13
  •  3
  •   cate    11 年前

    有一段时间,我一直在使用一个从上面几个采用宏的网站。我的重点是登录控制台,重点是 受控过滤冗长 ;如果您不介意大量的日志行,但希望轻松地打开和关闭它们的批,那么您可能会发现这很有用。

    首先,我可以选择用上面@rodrigo描述的printf替换nslog。

    #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
    

    接下来,我打开或关闭登录。

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

    在主块中,定义 类别 与应用程序中的模块相对应。同时定义日志记录 水平 上面不会调用日志记录调用。然后定义各种 风味 NSLO输出

    #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
    

    因此,对于klogifcategory和klogifdetailteq的当前设置,调用

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

    会打印但不会

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

    也不会

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

    如果要覆盖单个日志调用的设置,请使用负级别:

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

    我发现每行输入的几个额外字符都是值得的。

    1. 打开或关闭整个类别的注释(例如,仅报告标记为model的调用)
    2. 报告更高级别号码或最重要的电话号码更低的细节

    我相信很多人会觉得这有点过分,但只是以防万一,有人发现这符合他们的目的。