在发布 iPhone 应用时,如果禁用 NSLog();
,它会表现更好吗?
有一种方法是进入您的构建设置,在调试配置下添加一个值到“预处理器宏”值中,例如:
DEBUG_MODE=1
请确保您仅对调试配置执行此操作,而不是Beta或Release版本。然后,在一个公共头文件中,您可以执行以下操作:
#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
现在在测试和调试时,请将NSLog
替换为DLog
。您将获得调试消息。当您准备发布Beta版本或最终版本时,所有这些DLog
行都会自动变为空白,不会有任何输出。这样就不需要手动设置变量或注释NSLogs
。选择构建目标即可完成此操作。
Xcode 5和iOS 7的更新
注意: 对于在发布版本中移除print()语句的Xcode 7 / Swift 2.1解决方案,请查看我的回答这里。
是的,你应该在发布代码中删除任何NSLog语句,因为它只会减慢你的代码速度,在发布版本中没有任何用处。幸运的是,在Xcode 5(iOS 7)中,自动删除所有NSLog语句非常简单。那么为什么不去做呢。
首先是三个步骤,然后是一些说明
1)在你的Xcode项目中,找到“yourProjectName-prefix.pch”文件(通常你会在“支持文件”组下找到它,就像你的main.m文件一样)
2)在'.pch'文件的末尾添加以下3行:
#ifndef DEBUG
#define NSLog(...);
#endif
3) 测试您的“调试”版本和“发布”版本之间的差异。一种方法是通过“编辑方案” - >“运行应用程序名称” - >在选项卡“信息”下,使用调试和发布之间的下拉框进行选择。在发布版本中,您将不会在调试控制台中看到任何NSLog输出!
这一切是如何工作的呢?
首先,必须知道预处理器相对比较“愚笨”,只是在调用编译器之前充当“文本替换器”。它通过将#define
语句后面的内容替换为您指定的任何内容来替换您的内容。
#define NSLog(...);
(...)
代表方括号()内的“任何内容”。同时注意末尾的;
。这并非严格必要,因为编译器会优化掉它,但我喜欢把它放在那里,因为这更加“正确”。
使用#ifdef
(如果定义)或#ifndef
(如果未定义)可以使define语句具有条件性。
在这里,我们写了#ifndef DEBUG
,这意味着“如果符号DEBUG未定义”。#ifdef
或#ifndef
需要用#endif
进行“关闭”处理。
Xcode 5在构建模式为“DEBUG”时,默认为我们定义了“DEBUG”符号。在“release”中,此符号未定义。您可以在项目设置下验证此设置,选项卡“Build settings” -> 滚动到“Apple LLVM 5.0 - Preprocessing”部分 -> 预处理器宏。您将看到在发布版本中未定义符号“DEBUG”!
最后,.pch文件由Xcode自动创建,并在编译时自动包含在每个源文件中。因此,这就像是您将整个#define
事物放入每个源文件中一样。
NSLog
语句,而不考虑其中的内容。 - Eric PlatonNSLog
作为一个无操作语句,例如 if(AllCool) NSLog(@"Cool!Do Nothing!"); else...
而是将 NSLog
放在一些花括号中 if(AllCool) {NSLog(@"Cool!Do Nothing!");} else...
。 - arcady bob我个人最喜欢使用可变参数宏。
#ifdef NDEBUG
#define NSLog(...) /* suppress NSLog when in release mode */
#endif
除了那些明智地评论说在生产中根本不调用NSLog()
的所有人之外,我要补充一点:
所有这些NSLog()
输出字符串都可以被任何从商店下载并将设备插入运行Xcode的Mac电脑(通过组织者窗口)的人看到。
取决于您记录的信息(特别是如果您的应用程序联系服务器、进行身份验证等),这可能是一个严重的安全问题。
print()
是否也是这样,但很可能是这样的。 - Nicolas Miari在Xcode中的当前项目默认设置中,NS_BLOCK_ASSERTIONS
宏将在发布版本中设置为1,并且在调试版本中设置DEBUG=1
。
因此,我更喜欢以下方法。
// 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
#define _DEBUG
。如果没有定义NS_BLOCK_ASSERTIONS
,那么这行代码将会定义_DEBUG
。 - AechoLiu所有的答案都很好,然而这里有另外一个小技巧,你可以在应用程序的开发/测试阶段考虑使用它。
如果你只想关闭你的调试代码而不关闭可能指示你的代码直接控制范围之外问题的消息,则也可以对应用发布代码有用。
技巧:
您可以通过在.m文件顶部简单地包含以下行来关闭NSLog::
#define NSLog(...)
(注意:不要将此代码放在 .h 文件中,只需放在 .m 文件中!)
这只是让编译器通过展开预处理宏来评估 NSLog()
。该宏仅仅是去掉了参数。
如果你想再次启用它,你可以随时使用
#undef NSLog
#define NSLog(...)
-(void) myProblematicMethodThatSometimesNeedsDebugging {
...
}
#undef NSLog
是的,你应该禁用它。特别是如果你想要最大化代码的速度。过多地使用NSLog会污染系统日志,其他开发人员可能需要查找这些日志,并且它可能对速度关键的代码(例如循环内部等)产生重大影响。我曾经在一个递归函数中留下了一些日志消息,几周后发布了一个“30%速度提升!”的更新... ;-)
NSLog很慢,不应在发布版本中使用。像下面这样的简单宏将禁用它以及您可能有的任何断言,这些断言也应该被禁用。在较少见的情况下,您确实希望在发布版本中使用NSLog,请直接调用它。不要忘记将“-DNDEBUG”添加到您的“其他c标志”构建设置中。
#ifdef NDEBUG
#define MYLog(f, ...)
#else
#define MYLog(f, ...) NSLog(f, ## __VA_ARGS__)
#endif
在pch文件的#endif之前写下以下内容:
#define NSLog() //
NSLog()
。NSLog()
需要时间来执行,并为应用程序的运行时增加了额外的开销。无论如何,如果使用一个简单的 DEBUG 预处理器宏可以提高性能,那么我们应该禁用它。 - Scott