ChatGPT解决这个技术问题 Extra ChatGPT

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

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

特别是,我有两个问题:

有没有办法轻松 NSLog 当前方法的名称/行号?

有没有办法在编译发布代码之前轻松“禁用”所有 NSLog?

第一个问题,最喜欢的(明星)比赞成票更多... +1 ..

d
diederikh

以下是一些我经常使用的关于 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 宏仅用于在设置了 DEBUG 变量时输出(项目的 C 标志中的 -DDEBUG 用于调试配置)。

ALog 将始终输出文本(如常规 NSLog)。

输出(例如 ALog(@"Hello world") )将如下所示:

-[LibraryController awakeFromNib] [Line 364] Hello world

为什么你有一个 ##?我认为这是为了将争论粘合在一起,但您并没有粘合任何东西。
这可以防止参数的可能宏扩展
通常,宏可能会发生这种情况。一些宏产生多行。总是使用大括号的另一个论点;-)。
great 和 cocos2d api 有类似的日志语句。
(@"%s [Line %d] " fmt) 是如何导致将 fmt 附加到控制字符串的?除了这个调试宏之外,我还没有看到这种语法。
S
Sujay

我从上面提取了 DLogALog,并添加了 ULog,这会引发 UIAlertView 消息。

总结一下:

只有设置了 DEBUG 变量时,DLog 才会像 NSLog 一样输出

ALog 总是会像 NSLog 一样输出

仅当设置了 DEBUG 变量时,ULog 才会显示 UIAlertView

#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

这是它的样子:

https://i.stack.imgur.com/uuoUm.png

+1 迪德里克


我也将使用 ULog 扩展我的 ALog+DLog 代码。很有用。
如果未在 DEBUG 中运行,此代码会在 Xcode 5.1 中导致未使用的变量错误:(
为什么某些#define 指令以分号结尾?
@Locutus因此您不必在 DLog 语句之后放置分号。这很有用,因为如果您这样做了,在发布版本中,DLog 将编译为空,并且您的代码中会留下一个悬空的分号。这不是错误,但根据您的设置,如果它跟在另一个分号之后,它可能会引发警告。
B
Ben Clayton
NSLog(@"%s %d %s %s", __FILE__, __LINE__, __PRETTY_FUNCTION__, __FUNCTION__);

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

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

C++ 中的 __FUNCTION__ 显示错位名称 __PRETTY_FUNCTION__ 显示漂亮的函数名称,在可可中它们看起来相同。

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

#define NSLog

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


S
SEQOY Development Team

这是我们使用的一大组调试常量。享受。

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

你在哪里以及如何实现这一点?
R
Rodrigo

有一个没有答案的新技巧。您可以使用 printf 代替 NSLog。这将为您提供一个干净的日志:

使用 NSLog,您可以获得如下内容:

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

但是使用 printf 您只能得到:

Hello World

使用此代码

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

C
Community

我对 this question 的回答可能会有所帮助,看起来它类似于 Diederik 制作的那个。您可能还想用您自己的自定义日志记录类的静态实例替换对 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

因为您避开了 Apple 试图弃用的 %s 格式说明符并避免了 2015 年新引入的 -Wcstring-format-directive Clang 警告。
c
chunkyguy

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

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

而且,几乎像 NSLog 一样使用它:

SJLog(@"bye bye NSLogs !");

来自此博客:https://whackylabs.com/logging/ios/2011/01/19/ios-moving-in-and-out-of-nslogs/


Q
Quinn Taylor

为了补充上面的答案,在某些情况下使用 NSLog 的替代品非常有用,尤其是在调试时。例如,去掉每行中的所有日期和进程名称/ID 信息可以使输出更具可读性和启动速度更快。

以下链接提供了很多有用的弹药,可以让简单的日志记录变得更好。

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


A
AddisDev

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

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

这很棒!你将如何迅速做到这一点?
@AddisDev 我最喜欢这个。非常干净和简单。我只使用 NSLog。我不知道 DLog 和 ULog 是什么!谢谢。投票赞成...
@AddisDev我真的不明白为什么Apple默认不将这些至关重要的数据添加到 NSLog() ?奇怪的...
V
Venkat Reddy

这很简单,例如

-(void)applicationWillEnterForeground:(UIApplication *)application { NSLog(@"%s", __PRETTY_FUNCTION__); }

输出:-[AppDelegate applicationWillEnterForeground:]


D
Dickey Singh

在上述答案的基础上,这是我抄袭并提出的。还添加了内存记录。

#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

J
JOM

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


c
cate

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

首先,我可以选择用上面@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

在主块中,定义与应用程序中的模块对应的各种类别。还要定义一个日志级别,高于该级别的日志调用将不会被调用。然后定义各种风格的 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

因此,使用 kLOGIFcategory 和 kLOGIFdetailLTEQ 的当前设置,调用类似

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.

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

打开或关闭整个类别的评论(例如,仅报告那些标记为模型的呼叫)以更高级别的数字报告详细信息,或者仅报告以较低数字标记的最重要的呼叫

我相信很多人会觉得这有点矫枉过正,但以防万一有人发现它适合他们的目的..