当我编写某些内容时,一半的精力往往会花在添加清晰简洁的调试输出,或者在需要调试时可以启用/禁用的功能。
调试功能的一个示例是一个下载器类,我可以在其中打开#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...我还谈论上面的假装下载之类的东西。
When I write something, half the effort tends to go into adding clear and concise debug output, or functionality that can be enabled/disabled when that something needs debugging.
An example of debug functionality is a downloader class where I can turn on a #define which makes it "pretend" to download the file and simply hand me back the one I have already. That way I can test to see what happens when a user downloads a file, without having to wait for the network to physically grab the file every single time. This is great functionality to have, but the code gets messier with the #ifdefs.
I eventually end up with a bunch of #define
s like
// #define DEBUG_FOOMODULE_FOO
// #define DEBUG_BARMODULE_THINGAMAJIG
// ...
which are uncommented for the stuff I want to look at. The code itself turns out something like
- (void)something
{
#ifdef DEBUG_FOOMODULE_FOO
DebugLog(@"something [x = %@]", x);
#endif
// ...
#ifdef DEBUG_FOOMODULE_MOO
// etc
}
This works great for writing / maintaining the code, but it does nothing for the appearance of the code.
How do people write effortless on-the-fly long-term debug "stuff" anyway?
Note: I'm not only talking about NSLogging here... I'm also talking about stuff like the pretend-download above.
发布评论
评论(3)
在编写自己的库之前,我阅读了几个库,并看到了两种方法:宏 + C 函数 (NSLogger) 或宏 + Singleton (GTMLogger,Cocoa Lumberjack)。
我编写了我的幼稚实现 这里使用宏+单例。我在运行时执行此操作:
您可以对包而不是日志级别执行相同的操作。如果我想让它消失,我会更改#defines。以下是涉及的代码:
如果您想要对 Lumberjack 进行更复杂的了解,它有一个注册类工具来切换某些类的日志记录。
I read several libraries before writing my own and saw two approaches: macro + C functions (NSLogger) or macro + Singleton (GTMLogger, Cocoa Lumberjack).
I wrote my naive implementation here using macro + singleton. I do this during runtime:
You could do the same for packages instead log levels. If I want it gone, I change the #defines. Here is the code involved:
If you want something more sophisticated look into Lumberjack, it has a register class facility to toggle logging for some classes.
拥有两个函数,然后在运行时或编译时适当地选择它们对我来说似乎是一种干净的方法。这样就可以拥有一个
download.c
和一个download_debug.c
文件,其功能相同,但实现不同。如果您是否使用 -DDEBUG 进行构建,则链接到适当的链接。否则,使用函数指针对于运行时选择函数也同样有效。
如果您坚持将调试代码散布在您的函数中,那么您几乎会把自己设置为一团糟:)但是,您当然可以将这些片段分解为单独的函数,然后执行上述操作(或者使它们成为无操作,如在 DLog 示例中)。
Having two functions and then select them appropriately either at run-time or when compiling seems like a clean approach to me. This makes it possible to have one
download.c
and onedownload_debug.c
file with the same functions except with different implementations. Then link with the appropriate one if you are building with -DDEBUG or not.Otherwise, using function pointers works as well for run-time selecting functions.
If you insist of having debug code interspersed throughout your functions, you are pretty much setting up yourself for a mess :) But, you can of course break out those snippets into separate functions and then do the above (or make them no-ops as in the DLog example).
对于您的情况,您可以有单独的日志记录宏,例如
MooLog
和FooLog
,它们都根据单独的标志进行条件编译。你到处的复杂逻辑现在变成了这样:
For your case, you could have separate logging macros, say
MooLog
andFooLog
, that all conditionally compile based upon separate flags.Your complex logic everywhere now becomes this: