避免代码中的调试内容混乱

时间:2011-07-20 12:05:01

标签: iphone objective-c debugging coding-style code-cleanup

当我写东西时,一半的努力倾向于添加清晰简洁的调试输出,或功能,可以在需要调试时启用/禁用。

调试功能的一个示例是一个下载程序类,我可以在其中打开#define,使其“假装”下载文件并简单地将我还给我。这样我就可以测试用户下载文件时会发生什么,而不必等待网络每次都物理地抓取文件。这是很棒的功能,但#ifdefs的代码变得更加混乱。

我最终得到了一堆像#define一样的

// #define DEBUG_FOOMODULE_FOO
// #define DEBUG_BARMODULE_THINGAMAJIG
// ...

对于我想要查看的内容没有注释。代码本身就像

- (void)something
{
    #ifdef DEBUG_FOOMODULE_FOO
    DebugLog(@"something [x = %@]", x);
    #endif
    // ...
    #ifdef DEBUG_FOOMODULE_MOO
    // etc
}

这对于编写/维护代码非常有用,但它对代码的外观没有任何作用。

人们如何编写毫不费力的即时长期调试“东西”?

注意:我不只是在谈论NSLogging ...我也在讨论像上面假装下载这样的东西。

3 个答案:

答案 0 :(得分:2)

我在编写自己的库之前阅读了几个库,并看到了两种方法:宏+ C函数(NSLogger)或宏+单例(GTMLoggerCocoa Lumberjack)。

我使用宏+单例编写了我的天真实现here。我在运行时这样做:

[Logger singleton].logThreshold = kDebug;
trace(@"hi %@",@"world); // won't show
debug(@"hi %@",@"world);

您可以对包执行相同的操作,而不是日志级别。如果我想要它消失,我改变#defines。以下是涉及的代码:

#define trace(args...) [[Logger singleton] debugWithLevel:kTrace line:__LINE__ funcName:__PRETTY_FUNCTION__ message:args];

if (level>=logThreshold){
  // ...
} 

如果你想要更复杂的Lumberjack外观,它有一个寄存器类工具来切换某些类的日志记录。

答案 1 :(得分:1)

有两个函数,然后在运行时或编译时适当地选择它们对我来说似乎是一个干净的方法。这使得一个download.c和一个download_debug.c文件具有相同的功能,除了具有不同的实现。如果您正在使用-DDEBUG构建,则链接到相应的链接。

否则,使用函数指针也适用于运行时选择函数。

如果你坚持在整个函数中穿插调试代码,那么你几乎可以自己设置一个混乱:)但是,你当然可以将这些片段分解成单独的函数然后执行上面的操作(或者让它们不成功-ops与DLog示例中一样)。

答案 2 :(得分:0)

对于您的情况,您可以使用单独的日志记录宏,例如MooLogFooLog,它们都会根据单独的标志进行有条件的编译。

#ifdef DEBUG_FOO
#   define FooLog(fmt, ...) NSLog((@"%s [Line %d] " fmt), __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__);
#else
#   define FooLog(...)
#endif

#ifdef DEBUG_MOO
#   define MooLog(fmt, ...) NSLog((@"%s [Line %d] " fmt), __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__);
#else
#   define MooLog(...)
#endif

现在到处都是复杂的逻辑:

- (void)something
{
    // This only gets logged if the "DEBUG_FOO" flag is set.
    FooLog(@"something [x = %@]", x);
    // This only gets logged if the "DEBUG_MOO" flag is set.
    MooLog(@"Something else [y = %@]", y);
}