Answers:
预处理器宏确实非常适合调试。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
我发现将整个语句放在前缀标头而不是它自己的文件中比较容易。如果需要,可以通过使DebugLog与普通的Objective-C对象交互来构建更复杂的日志记录系统。例如,您可能有一个日志记录类,它会写入其自己的日志文件(或数据库),并包含一个可以在运行时设置的“ priority”参数,因此调试消息不会显示在您的发行版中,而错误消息是(如果执行此操作,则可以制作DebugLog(),WarningLog()等)。
哦,请记住#define DEBUG_MODE
可以在应用程序的不同位置重复使用。例如,在我的应用程序中,我使用它禁用许可证密钥检查,并且仅在特定日期之前允许应用程序运行。这使我能够以最小的努力分发时间有限,功能齐全的beta副本。
将这3行放在-prefix.pch文件的末尾:
#ifndef DEBUG
#define NSLog(...) /* suppress NSLog when in release mode */
#endif
您无需在项目中定义任何内容,因为DEBUG
在创建项目时默认情况下是在构建设置中定义的。
NSLog调用可以保留在生产代码中,但仅在真正例外的情况下才应存在,或将需要的信息记录到系统日志中。
乱扔系统日志的应用程序很烦人,而且不专业。
我无法评论Marc Charbonneau的答案,所以我将其发布为答案。
除了将宏添加到预编译的标头中之外,还可以使用Target构建配置来控制的定义(或缺少定义)DEBUG_MODE
。
如果选择“ 调试 ”,DEBUG_MODE
将定义活动配置,并且宏将展开为完整NSLog
定义。
选择“ 发布 ”活动配置将不会定义,DEBUG_MODE
并且发布版本中将NSLog
省略您的ging。
脚步:
GCC_PREPROCESSOR_DEFINITIONS
)DEBUG_MODE=1
DEBUG_MODE
未设置GCC_PREPROCESSOR_DEFINITIONS
如果您在定义中省略了'='字符,则会从预处理器中收到错误消息
另外,将此注释(如下所示)粘贴在宏定义上方,以提醒您DEBUG_MACRO
定义来自何处;)
// Target > Get Info > Build > GCC_PREPROCESSOR_DEFINITIONS
// Configuration = Release: <empty>
// = Debug: DEBUG_MODE=1
DEBUG_MODE
并且DEBUG_MACRO
是非常规的。我DEBUG_MACRO
在苹果网站(opensource.apple.com/source/gm4/gm4-15/src/m4.h?txt)上仅找到一个参考。也许更标准DEBUG
,NDEBUG
将是更好的选择?NDEBUG
由Posix指定;而DEBUG
按惯例使用。
编辑:Marc Charbonneau发布的方法,由sho引起了我的注意,它远胜于此方法。
我已经删除了答案的一部分,该部分建议在禁用调试模式时使用空函数来禁用日志记录。设置自动预处理程序宏的部分仍然相关,因此仍然存在。我还编辑了预处理器宏的名称,以使其更适合Marc Charbonneau的答案。
要在Xcode中实现自动(和预期的)行为:
在项目设置中,转到“构建”选项卡,然后选择“调试”配置。找到“预处理器宏”部分,然后添加一个名为的宏DEBUG_MODE
。
...
编辑:请参见Marc Charbonneau的答案,以了解启用和禁用DEBUG_MODE
宏记录的正确方法。
简单的事实是,NSLog只是很慢。
但为什么?为了回答这个问题,让我们找出NSLog的功能,然后看看它是如何做到的。
NSLog到底做什么?
NSLog做两件事:
它将日志消息写入Apple系统日志记录(asl)工具。这允许日志消息显示在Console.app中。它还检查是否将应用程序的stderr流发送到终端(例如,通过Xcode运行应用程序时)。如果是这样,它将日志消息写入stderr(以便它显示在Xcode控制台中)。
写入STDERR听起来并不困难。可以使用fprintf和stderr文件描述符参考来完成。但是asl呢?
我发现的有关ASL的最佳文档是Peter Hosey撰写的10部分博客文章:链接
无需赘述,重点(涉及性能)如下:
要将日志消息发送到ASL设施,您基本上可以打开与ASL守护程序的客户端连接并发送消息。但是-每个线程必须使用单独的客户端连接。因此,为了确保线程安全,每次调用NSLog时,它都会打开一个新的asl客户端连接,发送消息,然后关闭该连接。
如其他答案所述,您可以使用#define更改在编译时是否使用NSLog。
但是,更灵活的方法是使用可可伐木工人之类的日志记录库,该库允许您更改是否在运行时也记录了某些内容。
在您的代码中,用DDLogVerbose或DDLogError等替换NSLog,为宏定义等添加#import并设置记录器,通常是在applicationDidFinishLaunching方法中。
为了与NSLog具有相同的效果,配置代码为
[DDLog addLogger:[DDASLLogger sharedInstance]];
[DDLog addLogger:[DDTTYLogger sharedInstance]];
从安全角度来看,这取决于要记录的内容。如果NSLog
(或其他记录器)正在写入敏感信息,则应在生产代码中删除记录器。
从审核的角度来看,审核员不想查看每次使用NSLog
以确保其不会记录敏感信息。他/她只会告诉您删除记录器。
我与两个小组一起工作。我们审核代码,编写编码指南等。我们的指南要求在生产代码中禁用日志记录。所以内部团队知道不要尝试;)
我们也将拒绝登录生产的外部应用程序,因为我们不希望承担与意外泄露敏感信息有关的风险。我们不在乎开发人员告诉我们什么。根本不值得我们花时间调查。
记住,我们定义的是“敏感的”,而不是开发人员;)
我也认为一个执行大量日志记录的应用程序可以立即崩溃。有一个原因是执行/需要执行大量日志记录,并且通常情况下不稳定。它带有“看门狗”线程,可以重新启动挂起的服务。
如果您从未经历过安全体系结构(SecArch)审查,那么这些就是我们要关注的事情。
我强烈建议使用TestFlight进行日志记录(免费)。他们的方法将覆盖NSLog(使用宏),并允许您打开/关闭对NSLog的所有现有调用的日志记录(它们的服务器),Apple System日志和STDERR日志。这样做的好处是,您仍然可以查看已部署到测试仪的应用程序和已部署到App Store的应用程序的日志消息,而日志不会显示在用户的系统日志中。两全其美的。