Objective-C:从“Distribution”/生产构建中删除NSLog调用?
Objective-C:从“Distribution”/生产构建中删除NSLog调用?
更新:
这里有更多相关信息:
~~~~~~~~~~~~~~~~~~~~~~~~
情况
我在我的应用程序的复杂部分调试时,使用了一些相当庞大的NSLog调用。然而,最近我才了解到这些调用会影响运行时性能!
目标
我希望在任何不实际执行“Product > Run”(即Command-R)的情况下,都能够移除我的NSLog调用 - 尤其是在这个应用程序部署到App Store上时,以及在与Xcode断开连接时运行应用程序(例如,在街上走路时只是点击图标)。
提议的解决方案?
假设我已经创建了一个名为VIEW_DEBUG的预处理器宏,以下实现能否有效地在上述情况下移除NSLog调用?
<一些代码> #ifdef VIEW_DEBUG NSLog(@"非常复杂的日志条目"); #endif <更多的代码>
这对我来说很难“测试”,所以我想向更有经验的人求助。:)
Xcode设置(供参考)
Objective-C: 在发布版本中删除 'Distribution' 的 NSLog 调用
在开发过程中,我经常在代码中使用 DLog,它运行得很好。下面是我在代码中使用 DLog 的示例:
// DLog 几乎可以直接替换 NSLog
// DLog();
// DLog(@"here");
// DLog(@"value: %d", x);
// 不幸的是,DLog(aStringVariable) 并不能正常工作,你需要使用 DLog(@"%@", aStringVariable) 代替。
#ifdef DEBUG
# define DLog(fmt, ...) NSLog((@"%s [Line %d] " fmt), __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__);
#else
# define DLog(...)
#endif
// ALog 不受 DEBUG 设置的影响,始终会显示输出
#define ALog(fmt, ...) NSLog((@"%s [Line %d] " fmt), __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__);
更多信息:The Evolution of a Replacement for NSLog
问题出现的原因:
这段代码中的 DLog 和 ALog 宏定义在 DEBUG 模式下会调用 NSLog,而在发布版本中不需要这些调试信息。因此,问题的出现是因为在发布版本中仍然存在 NSLog 的调用。
解决方法:
为了在发布版本中删除 NSLog 的调用,我们需要修改宏定义 DLog 和 ALog。我们可以使用预处理指令来判断当前代码是否处于 DEBUG 模式,并根据判断结果来定义 DLog 和 ALog 的行为。
解决方法如下:
#ifdef DEBUG
# define DLog(fmt, ...) NSLog((@"%s [Line %d] " fmt), __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__);
#else
# define DLog(...)
#endif
在发布版本中,我们可以通过在预处理指令中定义 NDEBUG 来禁用 DEBUG 模式。这样,所有的 DLog 和 ALog 调用都会被替换为空。
#ifdef NDEBUG
# define DLog(...)
# define ALog(...)
#endif
通过以上修改,我们可以在发布版本中删除 NSLog 的调用,从而提高应用程序的性能和安全性。
问题原因:在开发过程中,我们通常会使用NSLog来输出调试信息,但是在发布版本中,我们不希望包含这些调试信息。因此,我们需要一种方法来自动删除或禁用发布版本中的NSLog语句。
解决方法:一种常见的解决方法是在前缀文件中添加以下代码(或者您可以创建一个专用的类,然后在需要的地方#include它):
#ifdef DEBUG #define DebugLog(...) NSLog(__VA_ARGS__) #else #define DebugLog(...) while(0) #endif
Xcode在执行调试构建时已经为我们定义了DEBUG(如您的屏幕截图所示)。`__VA_ARGS__`是一种在C99中引入的创建可变参数宏的方法。`do/while`确保即使DebugLog什么也不做,它仍具有相同的语法效果 - 不必担心无意义的循环,优化器将为您删除它。
然后,您可以像使用NSLog一样使用DebugLog。这样做与您提出的使用VIEW_DEBUG的方法完全相同,但您不需要一次又一次地复制和粘贴#ifdef条件。
`#define DebugLog(...) NSLog(__VA_ARGS__)`也可以工作。此外,对于GCC或LLVM,您不需要do {} while(0),`#define DebugLog(...)`也可以正常工作。
感谢两位评论者(尽管我无法同时@两位)- 这就是我从我打开的一个项目中盲目复制并粘贴所得到的。我接受了您的更正,并将其标记为社区wiki,因为现在它不会非常准确地声称对答案拥有所有权。
这就是它的基本含义 - 当定义了DEBUG时,您将获得一个行为与您键入NSLog完全相同的DebugLog(或任何您想要的名称),否则就会像您键入while(0)或什么也不写。它只取决于构建的类型,而不取决于设备是否连接,但它会阻止您发布日志,并且您无法从开发构建中对发布性能进行准确评估 - 这就是为什么当您使用Instruments进行性能分析时,它会自动执行发布构建的原因。