在 Swift 项目中为生产禁用 NSLog

Posted

技术标签:

【中文标题】在 Swift 项目中为生产禁用 NSLog【英文标题】:Disabling NSLog For Production In Swift Project 【发布时间】:2015-01-09 12:22:27 【问题描述】:

所以这个答案Do I need to disable NSLog before release Application? 提供了一种在生产环境中禁用 NSLog 的好方法,但不幸的是,这个解决方案似乎不适用于 Swift 项目。我的方法是将以下代码放在我用于项目中某些 pod 的桥接头 .h 文件中。

#ifdef DEBUG
    #define DLog(...) NSLog(@"%s %@", __PRETTY_FUNCTION__, [NSString stringWithFormat:__VA_ARGS__])
#else
    #define DLog(...) do   while (0)
#endif

但是,在 Swift 代码中使用 DLog 会导致编译器声明它们是无法识别的符号。我应该把这个#ifdef 放在其他地方吗?或者一般来说 Swift 项目有不同的解决方案吗?

【问题讨论】:

【参考方案1】:

您需要设置编译器标志以使用 Swift 预处理器 - 转到构建设置的 Swift 编译器 - 自定义标志 部分以设置 -D DEBUG 标志:

然后在您的代码中,您可以定义一个DLog() 函数,并且仅在设置了DEBUG 标志时才打印您的消息:

func DLog(message: String, function: String = #function) 
    #if DEBUG
    println("\(function): \(message)")
    #endif

【讨论】:

我实际上已经添加了-D DEBUG 标志,但还是谢谢你。你会建议我把这个功能放在哪里,这样它就可以在全球范围内看到?这种方法看起来很有趣。 它可以在使用你的模块/应用程序编译的任何文件中——在 AppDelegate.swift 文件中就可以了,或者你可以为全局常量创建一个单独的文件等。 我想我们可以依靠编译器来优化空函数调用? 提供的println()print() Swift 2.0)函数接受StringNSString 参数。我怎样才能在DLog()的签名中达到同样的效果? 哦,算了...我在文档的 print() 签名中找到了解决方案。看我的回答。【参考方案2】:

我是一个相当初级的开发人员,有时需要更清楚地定义一些东西来遵循。我在遇到类似问题时遇到了麻烦,改为替换 println(),当我问这个问题时,我的查询被标记为这个问题的重复。

经过大量的研究、试验、错误、错误、错误和错误!!,我发现我需要遵循的顺序是:

    单击 Xcode 项目窗口左侧文件导航器顶部的项目名称。这是包含项目名称、构建目标数量和 ios SDK 版本的行。 选择 Build Settings 选项卡并向下滚动到底部附近的“Swift Compiler - Custom Flags”部分。点击Other Flags旁边的向下箭头以展开该部分。 单击Debug 行将其选中。将鼠标光标放在该行的右侧并双击。将出现一个列表视图。单击列表视图左下方的 + 按钮以添加值。文本字段将变为活动状态。 在文本字段中,输入文本-D DEBUG 并按Return 提交该行。

    向您的项目添加一个新的 Swift 文件。您将要为该文件创建一个自定义类,因此请按照以下行输入文本:

    class Log 
    
       var intFor : Int
    
      init() 
        intFor = 42
      
    
      func DLog(message: String, function: String = __FUNCTION__) 
        #if DEBUG
          println("\(function): \(message)")
        #endif
      
    
    

(我今天在让类 init 被 Xcode 接受时遇到了麻烦,所以 init 可能比必要的要重一些。)

    现在您需要在任何您打算使用新自定义函数的类中引用您的自定义类来代替 println() 将其作为属性添加到每个适用的类中:

       let logFor = Log()
    

    现在您可以将println() 的任何实例替换为logFor.DLog()。输出还包括调用该行的函数的名称。

    请注意,在类函数内部我无法调用该函数,除非我将该函数复制为该类中的类函数,并且println() 的输入也更灵活一点,所以我不能在我的代码中的每个实例中都使用它。

【讨论】:

【参考方案3】:

查看有关编写断言here 的 Apple Swift 博客条目

简单来说,答案就是把DLog写成:

func DLog(message:String, function:String = __FUNCTION__) 
#if !NDEBUG
    NSLog("%@, %@", function, message)
#endif

【讨论】:

你会建议我把这个功能放在哪里,这样它就可以在全球范围内使用?在我的AppDelegate? 对于这样的东西,我通常会创建一个单独的文件。我的版本放在“Logging.swift”中 看起来最相关的答案。需要注意的一件事是,从 Swift 3 开始,__FUNCTION__ 已被弃用。相反,应使用#function 代替__FUNCTION__【参考方案4】:

下面,我修改了上面给出的 Nate Cook 的答案。此版本适用于 StringNSString 参数:

func DLog<T>(message:T, function: String = __FUNCTION__) 
    #if DEBUG
        if let text = message as? String 

            print("\(function): \(text)")
        
    #endif

当你需要做这样的事情时,它会很方便:

DLog("Received data:")
DLog(NSString(data:httpResponseBodyData, encoding:NSUTF8StringEncoding))

【讨论】:

【参考方案5】:

纯魔法_isDebugAssertConfiguration() 做所有事情,而不是Custom Flags 相关的混乱:

func log<T>(argument: T, file: String = #file, line: Int = #line, function: String = #function) 
    guard _isDebugAssertConfiguration() else 
        return
    

    let fileName = NSURL(fileURLWithPath: file, isDirectory: false).URLByDeletingPathExtension?.lastPathComponent ?? "Unknown"

    print("\(fileName)@\(line)/\(function): \(argument)")

在此处查看有关它的更多信息(和选项):https://***.com/a/34532569/496389。

【讨论】:

【参考方案6】:
#if DEBUG
#else
public func NSLog(_ format: String, _ args: CVarArg...)

    // noop

#endif

导致此的任务:swift debugPrint vs print

【讨论】:

【参考方案7】:

我刚刚发现了这个惊人的全局函数: https://gist.github.com/Abizern/a81f31a75e1ad98ff80d

这与 Nate Cook 的回答相匹配,并额外打印遇到的调试打印语句的文件名和行号。

【讨论】:

尝试在这里注册代码,因为链接可能不可用。 @uclagamer 我们在 *** 上的做法是在答案中包含代码,而不仅仅是链接到其他地方的代码。我猜这就是你被否决的原因。【参考方案8】:

我同意 uclagamer 的回答,它本质上是包装在预处理器条件中的增强打印功能:

func gLog<T>(@autoclosure object: () -> T, _ file: String = __FILE__, _ function: String = __FUNCTION__, _ line: Int = __LINE__)
    
    #if DEBUG
        let value = object()
        let stringRepresentation: String

        if let value = value as? CustomDebugStringConvertible
            
            stringRepresentation = value.debugDescription
            
        else if let value = value as? CustomStringConvertible
            
            stringRepresentation = value.description
            
        else
            
            fatalError("gLog only works for values that conform to CustomDebugStringConvertible or CustomStringConvertible")
            

        let fileURL = NSURL(string: file)?.lastPathComponent ?? "Unknown file"
        let queue = NSThread.isMainThread() ? "UI" : "BG"
        let gFormatter = NSDateFormatter()
        gFormatter.dateFormat = "HH:mm:ss:SSS"
        let timestamp = gFormatter.stringFromDate(NSDate())

        print("\(timestamp) \(queue) = \(fileURL) | \(function)[\(line)]: " + stringRepresentation)
    #endif
    

这是为 Swift 2.0 更新的。所有功劳归功于 Abider Nasir。他的原始博客文章(和链接的要点)可以在这里找到:

http://abizern.org/2015/02/01/debug-logging-in-swift/

重要提示:如果有人正在努力寻找“Swift 编译器 - 构建设置的自定义标志部分”,这已被多次提及,您需要确保显示“所有”构建设置,而不仅仅是“基本”构建设置,是默认设置。

【讨论】:

以上是关于在 Swift 项目中为生产禁用 NSLog的主要内容,如果未能解决你的问题,请参考以下文章

从现有 Xcode 项目中为 Swift 包管理器导出 Package.swift

如何在swift中隐藏/禁用标签栏项目

如何在单个 iOS 项目/应用程序中为发布和调试模式(测试和生产环境)制作不同的 Firebase 数据库?

在 Vue.js 2.x 中为选定的 NPM 包禁用 eslint

在 Swift 中为 macOS 构建框架时出错

在 Swift 中为变量属性赋值的 Objective C 语法