我需要在发布应用程序之前禁用 NSLog 吗?

当发布一个 iPhone 应用程序时,如果我禁用 NSLog();,它会表现得更好吗?

52204 次浏览

是的,你应该关掉它。特别是当您试图最大限度地提高代码的速度时。NSLogging 会污染其他开发人员可能试图深入研究的系统日志,并且可能对速度至关重要的代码(内部循环等)产生重大影响有一次,我不小心在递归函数中留下了一些日志消息,结果发布了一个更新,速度提高了30% 几个星期后... ; -)

一种方法是进入构建设置,在 Debug 配置下向“预处理器宏”值添加一个值,如下:

DEBUG_MODE=1

请确保您只为调试配置而不是为 Beta 或发布版本这样做。然后在一个常见的头文件中,您可以执行以下操作:

#ifdef DEBUG_MODE
#define DLog( s, ... ) NSLog( @"<%p %@:(%d)> %@", self, [[NSString stringWithUTF8String:__FILE__] lastPathComponent], __LINE__, [NSString stringWithFormat:(s), ##__VA_ARGS__] )
#else
#define DLog( s, ... )
#endif

现在到处使用 DLog而不是 NSLog。在测试和调试时,您将收到调试消息。当您准备发布测试版或最终版时,所有这些 DLog行都会自动变为空白,不会发出任何内容。这样就不需要手动设置变量或者注释 NSLogs。选择构建目标就可以解决这个问题。

NSLog 速度很慢,不应该用于版本构建。像下面这样的一个简单宏将禁用它以及任何您可能拥有的也应该禁用的断言。在不太常见的情况下,如果您确实希望在发布版本中使用 NSLog,那么只需直接调用它。不要忘记添加“-DNDEBUG”到您的“其他 c 标志”构建设置。

#ifdef NDEBUG
#define MYLog(f, ...)
#else
#define MYLog(f, ...) NSLog(f, ## __VA_ARGS__)
#endif

Project Default Setting

Inside current default setting of project in Xcode, the NS_BLOCK_ASSERTIONS macro will be set to 1 in release version, and DEBUG=1 in Debug version.

所以,我更喜欢下面的方法。

// NS_BLOCK_ASSERTIONS is defined by default, as shown in the screenshot above.
// Or, you can define yourself Flags in the `Other C Flags` -> `Release`.
#ifndef NS_BLOCK_ASSERTIONS
#define _DEBUG
#endif


#ifdef _DEBUG
// for debug mode
#define DLog(fmt,...) NSLog(@"%s " fmt, __FUNCTION, ##__VA_ARGS__)
... /// something extra
#else
// for release mode
#define DLog(fmt,...) /* throw it away */
... /// something extra
#endif

这个怎么样?

#ifndef DEBUG_MODE
fclose(stderr);     // the simplest way to disable output from NSLog
#endif

我个人最喜欢使用变量宏。

#ifdef NDEBUG
#define NSLog(...) /* suppress NSLog when in release mode */
#endif

几乎所有上述答案都提出了一个解决方案,但没有解释问题。我在谷歌上搜索了一下,找到了原因。我的回答是:

是的,如果您在您的发布版本中注释掉 NSLog,那么性能将会变得更好。因为 NSLog 太慢了。为什么?NSLog 将做两件事: 1)将日志消息写入 Apple System Logging (ASL) ; 2)如果应用程序运行在 xcode 中,它也将日志消息写入 stderr。

主要问题在于第一个。为了实现线程安全,每次调用 NSLog,它都会打开到 ASL 设施的连接,发送消息,并关闭连接。连接操作非常昂贵。另一个原因是 NSLog 花费一些时间来记录时间戳。

来自 here的参考文献。

在 pch 文件中,在 # endf 之前写下这个

#define NSLog() //

这些都是不错的答案,不过这里还有一个你可以考虑使用的小技巧,主要是在你的应用程序的开发/测试阶段。

如果你只想关闭你的调试代码,而不是那些可能指示代码直接控制之外的问题的消息,那么它对应用发布代码也是有用的。

诀窍:

You can turn off NSLog per .m file by simply including the follow line at the top of the .m file:

#define NSLog(...)

(注意: 做 < em > NOT 把这个. h 文件,只有. m 文件!)

这只是让编译器通过展开预处理器宏来计算 NSLog()。宏除了去掉参数之外什么也不做。

如果你想重新打开它,你可以随时使用

#undef NSLog

例如,您可以通过执行以下操作来阻止对特定方法组周围的 NSLog 的调用

#define NSLog(...)
-(void) myProblematicMethodThatSometimesNeedsDebugging {
...
}
#undef NSLog

除了那些明智地评论说在生产环境中根本不调用 NSLog()的人运行速度稍微快一些之外,我还要补充一点:

所有这些 NSLog()输出字符串对任何从商店下载应用程序并将设备插入运行 Xcode (通过 Organizer 窗口)的 Mac 运行它的人都是可见的。

取决于您记录的信息(特别是如果您的应用程序与服务器联系,进行身份验证等) ,这可是个严重的安全问题

更新 Xcode 5和 iOS 7

注意: 对于在发布版本中删除 打印()语句的 Xcode 7/Swift 2.1解决方案,请找到我的答案 给你

是的,您应该删除发行版代码中的任何 NSLog 语句,因为它只会降低代码速度,而且在发行版中没有任何用处。幸运的是,在 Xcode 5(iOS 7)中,在版本构建中“自动”删除所有 NSLog 语句非常简单。那为什么不这么做呢。

First the 3 steps to take, then some explanation

1)在 Xcode 项目中,找到‘ yourProjectName-前缀。Pch’file (通常您会在 main.m 文件所在的“支持文件”组下找到这个文件

2)在“ . pch”文件末尾添加以下3行:

#ifndef DEBUG
#define NSLog(...);
#endif

3)测试你的“调试”和“发布”版本之间的区别。一种方法是通过“编辑方案”-> “运行应用程序名称”-> 在“信息”选项卡下使用调试和发布之间的下拉框进行选择。在发布版本中,您不会在调试控制台中看到任何 NSLog 输出!

这是怎么回事?

首先,我们必须知道预处理器相对来说是“哑的”,在调用编译器之前,它只是充当“文本替换器”。它用 #define语句之后的内容替换“ # Definition”中的任何内容。

#define NSLog(...);

(...)表示括号()之间的“任何东西”。还要注意结尾的 ;。这并不是严格意义上的必要,因为编译器会优化它,但我喜欢把它放在那里,因为它更“正确”。在我们的 #define之后有一个“无”,所以预处理器将用“无”替换它,所以它将丢弃完整的行,从 NSLog...开始,直到包括 ;

Definition 语句可以使用 #ifdef(如果定义了)或 #ifndef(如果没有定义)进行条件化

这里我们写 #ifndef DEBUG,意思是‘如果符号 DEBUG 没有被定义’。#ifdef#ifndef需要与 #endif“关闭”

Xcode 5 defines by default the 'DEBUG' symbol for us when de build mode is 'DEBUG'. In 'release' this is not defined. you can verify this under your project settings, tab 'Build settings' -> scroll down to the section 'Apple LLVM 5.0 - Preprocessing' -> preprocessor macros. You'll see that the symbol 'DEBUG' is not defined for release builds !

最后。Pch 文件由 Xcode 自动创建,并在编译期间自动包含在每个源文件中。因此,就好像您已经把整个 #define的事情放入您的每个源文件。

var showDebugLogs = false;


func DLog(format: String, args: CVarArgType...) {
if showDebugLogs{
println(String(format: format, arguments: args))
}
}

这也将接受额外的论点. 。 Just the showDebugLogs parameter value to true or false, as per your need