6

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

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

我最终得到了一堆#defines like

// #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 ... 我还在谈论上面的假装下载之类的东西。

4

3 回答 3

2

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

我在这里使用宏+单例编写了我的幼稚实现。我在运行时这样做:

[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 进行更复杂的研究,它有一个注册类工具来切换某些类的日志记录。

于 2011-07-20T13:35:28.890 回答
1

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

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

如果您坚持在整个函数中散布调试代码,那么您几乎是在为自己设置一团糟:) 但是,您当然可以将这些片段分解为单独的函数,然后执行上述操作(或将它们设为无操作)在 DLog 示例中)。

于 2011-07-29T12:39:26.197 回答
0

对于您的情况,您可以有单独的日志记录宏,比如MooLogand FooLog,它们都基于单独的标志有条件地编译。

#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);
}
于 2011-07-20T12:07:16.767 回答