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

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

我特别想问两个问题:

  • 是否有一种方法可以轻松地NSLog当前方法的名称/行号?
  • 在编译发布代码之前,是否有一种方法可以轻松地“禁用”所有nslog ?
145775 次浏览
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

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

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

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

输出(例如ALog(@"Hello world"))看起来像这样:

-[LibraryController awakeFromNib] [Line 364] Hello world

我对这个问题的回答可能有帮助,看起来它类似于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

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

下面的链接提供了很多有用的方法,可以使简单的日志记录变得更好。

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

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

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

禁用所有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/

我已经从上面取了DLogALog,并添加了ULog,它会引发UIAlertView消息。

总结:

  • 只有当DEBUG变量被设置时,DLog才会像NSLog一样输出
  • ALog将始终像NSLog那样输出
  • ULog仅在设置DEBUG变量时才显示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

这是它的样子:

Debug UIAlertView

+ 1 Diederik

新增的DLog。而不是完全删除调试从发布的应用程序,只是禁用它。当用户有问题时,这将需要调试,只需告诉如何在发布的应用程序中启用调试和通过电子邮件请求日志数据。

简短版本:创建全局变量(是的,懒惰和简单的解决方案),并修改DLog如下所示:

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

更长的答案在joromnius iLessons iLearned: 如何在发布的应用程序中动态调试日志

这是一个没有答案的新把戏。你可以使用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

在以上答案的基础上,以下是我抄袭并想出的答案。还添加了内存日志记录。

#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

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

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

一段时间以来,我一直在使用上面几个宏的站点。我的重点是登录控制台,重点是控制,过滤冗长;如果你不介意大量的日志行,但想要轻松地切换它们&关掉,你会发现这个很有用。

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

我发现每行多打几个字是值得的

  1. 打开或关闭整个评论类别(例如,只报告那些标记为Model的调用)
  2. 报告细节时使用较高级别的数字,或者只报告最重要的电话时使用较低的数字

我相信很多人会觉得这有点过分,但以防有人发现它适合他们的目的。

很简单,例如

-(void) applicationwillenter前台:(UIApplication *)application {

    NSLog(@"%s", __PRETTY_FUNCTION__);

< >强输出: - - - - - - [AppDelegate applicationWillEnterForeground:] < / p >