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

我正在做关于在Xcodedebugging的演示文稿,并希望得到更多关于高效使用NSLog的信息。

特别是我有两个问题:

  • 有没有办法轻松NSLog当前方法的名称/行号?
  • 有没有办法在编译发布代码之前轻松“禁用”所有的NSLogs?

下面是我使用了很多NSLog的一些有用的macros:

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

DLogmacros用于只在DEBUGvariables被设置时输出(debugging确认的项目的C标志中的-DDEBUG)。

ALog将总是输出文本(如常规的NSLog)。

输出(例如,ALog(@“Hello world”))将如下所示:

 -[LibraryController awakeFromNib] [Line 364] Hello world 

我已经从上面采取了DLogALog ,并且添加了引起UIAlertView消息的ULog

总结:

  • 只有当DEBUGvariables被设置时, DLog才会像NSLog一样输出
  • ALog将总是像NSLog一样输出
  • 仅当DEBUGvariables被设置时, ULog才会显示UIAlertView
 #ifdef DEBUG
 #define DLog(fmt,...)NSLog((@“%s [Line%d]”fmt),__PRETTY_FUNCTION__,__LINE__,## __ VA_ARGS__);
 #其他
 #define DLog(...)
 #万一
 #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 alert];  }
 #其他
 #定义ULog(...)
 #万一

这是它的样子:

调试UIAlertView

+1 Diederik

 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 

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

这里是我们使用的一大组debugging常量。 请享用。

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

有一个新的窍门,没有答案。 你可以用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 

我对这个问题的回答可能会有帮助,看起来就像Diederik熟悉的一样。 您可能还想用自己的自定义日志logging类的静态实例replace对NSLog()的调用,这样可以为debugging/警告/错误消息添加优先级标志,将消息发送到文件或数据库以及控制台,或几乎任何你能想到的。

 #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 

禁用所有的NSLogs,对于某些对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 !"); 

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

为了补充上面的答案,在某些情况下使用NSLog代替是非常有用的,特别是在debugging时。 例如,删除每行上的所有date和进程名称/ ID信息可以使输出更易读,更快启动。

下面的链接提供了相当有用的弹药,使简单的日志更好。

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

很容易改变你现有的NSLog来显示它们被调用的行号和类。 将一行代码添加到您的前缀文件中:

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

build立在上面的答案之上,这里是我剽窃和提出的。 还增加了记忆日志。

 #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 

例如,这很简单

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

  NSLog(@"%s", __PRETTY_FUNCTION__); 

}

输出: – [AppDelegate applicationWillEnterForeground:]

DLog的新增function 而不是完全从发布的应用程序中删除debugging,只能禁用它。 当用户遇到需要debugging的问题时,请告知如何在已发布的应用程序中启用debugging,并通过电子邮件请求日志数据。

短版本:创build全局variables(是的,懒惰和简单的解决scheme),并修改DLog是这样的:

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

在Jomnius iLessons上回答更长的问题: 如何在已发布的应用程序中执行dynamicdebugging日志logging

有一段时间我一直在使用从上面几个macros采用的网站。 我的重点是login控制台,重点是控制和过滤的冗长 ; 如果您不介意大量的日志行,但想要轻松切换批量日志,那么您可能会发现这很有用。

首先,我可以用上面@Rodrigo所描述的那样,用printfreplaceNSLog

 #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 

接下来,我打开或closureslogin。

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

在主程序块中,定义与应用程序中的模块相对应的各个类别 。 另外定义一个日志logging级别,高于此日志logging调用将不会被调用 然后定义各种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. 

我发现打印每行的额外字符是值得的,因为我可以

  1. 打开或closures整个类别的评论(例如只报告标有模型的呼叫)
  2. 报告更高级别的号码的细节,或只是最重要的呼叫号码较低

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