是不是应该在生产代码中使用NSLog()?

在这个网站我被告知了几次,但我想确保这是真的。

我希望能够在我的代码中遍历NSLog函数调用,并且在构build我的发布/分发版本时,Xcode / gcc会自动去除这些调用。

我应该避免使用这个? 如果是这样,经验丰富的Objective-C程序员之间最常见的select是什么?

预处理器macros确实非常适合debugging。 NSLog()没有什么错,但是用更好的function来定义你自己的日志函数是很简单的。 这里是我使用的一个,它包括文件名和行号,以便更容易追踪日志语句。

#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对象交互来构build一个更复杂的日志logging系统。 例如,你可以有一个logging类写入自己的日志文件(或数据库),并且包含一个可以在运行时设置的“优先级”参数,所以debugging消息不会在你的发布版本中显示,但是错误消息是如果你这样做,你可以做DebugLog(),WarningLog()等等)。

哦,请记住, #define DEBUG_MODE可以在应用程序的不同位置重新使用。 例如,在我的应用程序中,我使用它来禁用许可证密钥检查,只允许应用程序在特定date之前运行。 这使我能够以最小的努力分发一个有时间限制的,function完整的testing版本。

把这3行放在-prefix.pch文件的末尾:

 #ifndef DEBUG #define NSLog(...) /* suppress NSLog when in release mode */ #endif 

您不需要在项目中定义任何内容,因为在您创build项目时默认情况下, DEBUG是在您的构build设置中定义的。

NSLog调用可以保留在生产代码中,但是只能用于真正特殊情况,或者希望将其logging到系统日志中的信息。

垃圾系统日志的应用程序是烦人的,并认为是不专业的。

我不能评论Marc Charbonneau的回答 ,所以我会将其作为答复。

除了将macros添加到预编译头文件之外,还可以使用Target构buildconfiguration来控制DEBUG_MODE的定义(或缺less定义)。

如果select“ debugging ”活动configuration, DEBUG_MODE将被定义,并且macros扩展到完整的NSLog定义。

select“ 释放 ”活动configuration将不会定义DEBUG_MODE并且您的NSLog ging在发布版本中被忽略。

脚步:

  • 目标>获取信息
  • 生成选项卡
  • search“PreProcessormacros”(或GCC_PREPROCESSOR_DEFINITIONS
  • selectconfiguration: debugging
  • 在此级别编辑定义
  • 添加DEBUG_MODE=1
  • selectconfiguration: 释放
  • 确认DEBUG_MODE未在GCC_PREPROCESSOR_DEFINITIONS设置

如果在定义中省略了“=”字符,则会从预处理器中获得一个错误

另外,在macros定义上面粘贴这个注释(如下所示),以提醒您DEBUG_MACRO定义的来源;)

 // Target > Get Info > Build > GCC_PREPROCESSOR_DEFINITIONS // Configuration = Release: <empty> // = Debug: DEBUG_MODE=1 

编辑:由Marc Charbonneau张贴的方法 ,并引起了我的注意,是比这更好。

我已经删除了我的答案的部分,build议使用空function来禁用debugging模式禁用日志logging。 处理设置自动预处理器macros的部分仍然相关,所以它仍然存在。 我还编辑了预处理macros的名称,以便与Marc Charbonneau的答案更好地匹配。


为了在Xcode中实现自动(和预期的)行为:

在项目设置中,转到“Build”选项卡,然后select“Debug”configuration。 find“预处理器macros”部分,并添加名为DEBUG_MODE的macros。

编辑:请参阅Marc Charbonneau的正确方法来启用和禁用与DEBUG_MODEmacros的日志logging的DEBUG_MODE

我同意马修。 生产代码中的NSLog没有任何问题。 实际上,它对用户可能是有用的。 也就是说,如果您使用NSLog的唯一原因是帮助debugging,那么,是的,在发布之前应该将其删除。

此外,由于您已经将此标记为iPhone问题,NSLog需要资源,这是iPhone所珍惜的东西。 如果你是NSLogging的任何东西在iPhone上,这会从你的应用程序中消耗处理器的时间。 明智地使用它。

简单的事实是,NSLog只是简单的慢。

但为什么? 为了回答这个问题,我们来看看NSLog的function,以及它是如何实现的。

NSLog做了什么?

NSLog有两件事情:

它将日志消息写入Apple System Logging(asl)工具。 这允许日志消息显示在Console.app中。 它还会检查应用程序的stderrstream是否正在到达terminal(例如当应用程序正在通过Xcode运行时)。 如果是这样,它将日志消息写入stderr(以便它显示在Xcode控制台中)。

写STDERR听起来不难。 这可以通过fprintf和stderr文件描述符引用来完成。 但是呢?

我发现关于ASL的最好的文档是Peter Hosey的10篇博文: 链接

没有太多的细节,突出的(就性能而言)是这样的:

要发送一个日志消息到ASL设施,你基本上打开一个到ASL守护进程的客户端连接并发送消息。 但是 – 每个线程必须使用一个单独的客户端连接。 所以,为了线程安全,每次调用NSLog时,都会打开一个新的asl客户端连接,发送消息,然后closures连接。

资源可以在这里和这里find。

正如在其他答案中指出的那样,您可以使用#define来修改是否在编译时使用NSLog。

然而更灵活的方法是使用Cocoa Lumberjack之类的日志库,以便在运行时更改是否logging某些内容。

在你的代码中,用DDLogVerbose或DDLogError等代替NSLog,为macros定义等添加一个#import,并通常在applicationDidFinishLaunching方法中设置logging器。

为了与NSLog具有相同的效果,configuration代码是

 [DDLog addLogger:[DDASLLogger sharedInstance]]; [DDLog addLogger:[DDTTYLogger sharedInstance]]; 

从安全angular度来看,这取决于logging的内容。 如果NSLog (或其他logging器)正在编写敏感信息,则应删除生产代码中的logging器。

从审计的angular度来看,审计人员不希望查看每次使用NSLog以确保其不logging敏感信息。 他/她只会告诉你删除logging器。

我和两个团队一起工作。 我们审核代码,编写代码指南等。我们的指南要求在生产代码中禁用日志logging。 所以内部团队知道不要去尝试;)

我们也会拒绝login生产的外部应用程序,因为我们不想接受意外泄漏敏感信息的风险。 我们不在乎开发者告诉我们什么。 它根本不值得我们的时间来调查。

记住,我们定义“敏感”,而不是开发者;)

我也认识到一个应用程序执行大量的日志logging作为一个应用程序准备崩溃。 有很多原因需要logging,而且通常不稳定。 它的权利在那里与看门狗线程重新启动挂起的服务。

如果你从来没有经历过安全架构(SecArch)审查,那么这些就是我们所看到的。

你不应该在发布代码中不必要地使用printf或者NSLog。 尝试只做一个printf或NSLog如果应用程序发生了什么坏事,IE一个不可恢复的错误。

请记住,NSLogs可以减慢UI /主线程。 除非绝对必要,否则最好从发布版本中删除它们。

我强烈build议使用TestFlight进行日志logging(免费)。 他们的方法将覆盖NSLog(使用macros),并允许您打开/closureslogging到他们的服务器,苹果系统日志和STDERR日志,所有现有的调用NSLog。 关于这一点的好处是,您仍然可以查看部署到App Store中部署的应用程序的日志消息,而日志不会出现在用户的系统日志中。 两全其美的。