【问题标题】:Swift: print() vs println() vs NSLog()斯威夫特:print() vs println() vs NSLog()
【发布时间】:2014-11-15 01:38:22
【问题描述】:

printNSLogprintln 之间有什么区别,我应该什么时候使用它们?

例如,在 Python 中,如果我想打印字典,我只需要 print myDict,但现在我有 2 个其他选项。我应该如何以及何时使用它们?

【问题讨论】:

  • NSLog 和打印 NSDictionary 对我没有任何用处?
  • 从 iOS 10.0 开始,建议使用os_log。请看我的回答below
  • 除了在 os_log 上查看 Swift 文档:尝试查看 Objective-C 页面的 full documentation。它更加完整
  • ...和有效的iOS 14(和macOS 11等),使用Logger代替os_log

标签: swift debugging logging console oslog


【解决方案1】:

一些不同之处:

  1. printprintln:

    print 函数在调试应用程序时在 Xcode 控制台中打印消息。

    println 是它的一个变体,它在 Swift 2 中被删除并且不再使用。如果您看到使用 println 的旧代码,您现在可以安全地将其替换为 print

    在 Swift 1.x 中,print 没有在打印字符串的末尾添加换行符,而 println 可以。但是现在,print 总是在字符串末尾添加换行符,如果您不希望它这样做,请提供 ""terminator 参数。

  2. NSLog:

    • NSLog 在输出中添加时间戳和标识符,而print 不会;

    • NSLog 语句同时出现在设备的控制台和调试器的控制台中,而print 只出现在调试器的控制台中。

    • iOS 10-13/macOS 10.12-10.x 中的NSLog 使用printf-style 格式字符串,例如

        NSLog("%0.4f", CGFloat.pi)
      

      这将产生:

      2017-06-09 11:57:55.642328-0700 MyApp[28937:1751492] 3.1416

    • iOS 14/macOS 11 中的NSLog 可以使用字符串插值。 (然后,同样,在 iOS 14 和 macOS 11 中,我们通常更喜欢 Logger 而不是 NSLog。请参阅下一点。)

    如今,虽然 NSLog 仍然有效,但我们通常会使用“统一日志记录”(见下文)而不是 NSLog

  3. 有效的 iOS 14/macOS 11,我们有“统一日志”系统的Logger 接口。有关Logger 的介绍,请参阅 WWDC 2020 Explore logging in Swift

    • 要使用Logger,必须导入os

      import os
      
    • NSLog一样,统一日志也会同时向Xcode调试控制台和设备控制台输出消息

    • 创建一个Loggerlog 给它的消息:

      let logger = Logger(subsystem: Bundle.main.bundleIdentifier!, category: "network")
      logger.log("url = \(url)")
      

      当您通过外部控制台应用程序观察应用程序时,您可以根据subsystemcategory 进行过滤。将您的调试消息与 (a) 其他子系统代表您的应用生成的消息或 (b) 来自其他类别或类型的消息区分开来非常有用。

    • 您可以指定不同类型的日志消息,.info.debug.error.fault.critical.notice.trace 等:

      logger.error("web service did not respond \(error.localizedDescription)")
      

      因此,如果使用外部控制台应用程序,您可以选择仅查看某些类别的消息(例如,如果您在控制台“操作”菜单上选择“包含调试消息”,则仅显示调试消息)。这些设置还规定了许多关于事物是否记录到磁盘的微妙问题细节。有关详细信息,请参阅 WWDC 视频。

    • 默认情况下,非数字数据会在日志中进行编辑。在您记录 URL 的示例中,如果应用程序是从设备本身调用的,并且您正在通过 macOS 控制台应用程序观看,您将在 macOS 控制台中看到以下内容:

      url =

      如果您确信此消息不会包含用户机密数据,并且您希望在 macOS 控制台中查看字符串,则必须执行以下操作:

      os_log("url = \(url, privacy: .public)")
      
  4. 在 iOS 14/macOS 11 之前,iOS 10/macOS 10.12 引入了 os_log 用于“统一日志记录”。有关统一日志的一般介绍,请参阅 WWDC 2016 视频Unified Logging and Activity Tracing

    • 导入os.log:

      import os.log
      
    • 您应该定义subsystemcategory

      let log = OSLog(subsystem: Bundle.main.bundleIdentifier!, category: "network")
      

      当使用os_log 时,您将使用 printf 样式的模式而不是字符串插值:

      os_log("url = %@", log: log, url.absoluteString)
      
    • 您可以指定不同类型的日志消息,.info.debug.error.fault(或 .default):

      os_log("web service did not respond", type: .error)
      
    • 使用os_log 时不能使用字符串插值。例如 printLogger 你这样做:

      logger.log("url = \(url)")
      

      但是使用os_log,您必须这样做:

      os_log("url = %@", url.absoluteString)
      
    • os_log 强制执行相同的数据隐私,但您在 printf 格式化程序中指定公共可见性(例如 %{public}@ 而不是 %@)。例如,如果您想从外部设备查看它,您必须这样做:

      os_log("url = %{public}@", url.absoluteString)
      
    • 如果您想查看 Instruments 的活动范围,也可以使用“兴趣点”日志:

      let pointsOfInterest = OSLog(subsystem: Bundle.main.bundleIdentifier!, category: .pointsOfInterest)
      

      然后开始一个范围:

      os_signpost(.begin, log: pointsOfInterest, name: "Network request")
      

      最后以:

      os_signpost(.end, log: pointsOfInterest, name: "Network request")
      

      如需了解更多信息,请参阅https://stackoverflow.com/a/39416673/1271826

底线,print 足以使用 Xcode 进行简单的日志记录,但统一的日志记录(无论是 Logger 还是 os_log)实现了相同的目标,但提供了更强大的功能。

在调试必须在 Xcode 之外进行测试的 iOS 应用程序时,统一日志记录的威力会得到显着缓解。例如,在测试后台 iOS 应用程序进程(如后台获取)时,连接到 Xcode 调试器changes the app lifecycle。因此,您经常需要在物理设备上进行测试,从设备本身运行应用程序,而不是从 Xcode 的调试器启动应用程序。统一日志记录让您仍然可以从 macOS 控制台应用程序查看您的 iOS 设备日志语句。

【讨论】:

  • 不错的总结!再补充一点:您可以将 NSString 传递给 println,但不能传入 NSLog;您可以为 NSLog 添加参数,但不能添加 println; NSLog 的 Swift 样式字符串插值有时会崩溃,但 println 不会。
  • 关于 Swift 编译器优化和 print() 使用的有趣说明 medium.com/ios-os-x-development/…
  • @Rob 如果我使用 print 那么它会出现在调试器控制台中吗?还是我们应该使用 debugPrint?
  • 如果你使用print,它会出现在Xcode的调试区,就像debugPrint一样。唯一的区别是print最终调用了对象的description方法,而debugPrint调用了debugDescription,这可能比description更冗长。
  • @Rob,您的回答似乎解决了登录 Swift 的问题。自从我升级到 Xcode 9 stackoverflow.com/q/46397444/2348597 后,我试图将此与我在 Objective C 中遇到的 NSLog 问题联系起来
【解决方案2】:

如果您使用的是 Swift 2,现在您只能使用 print() 向输出写入内容。

Apple 已将 println()print() 函数合并到 一个。

已更新至 iOS 9

默认情况下,该函数通过添加换行符来终止它打印的行。

print("Hello Swift")

终结者

要打印一个没有换行符的值,传递一个空字符串作为终止符

print("Hello Swift", terminator: "")

分隔符

您现在可以使用分隔符连接多个项目

print("Hello", "Swift", 2, separator:" ")

两者

或者你可以这样组合使用

print("Hello", "Swift", 2, separator:" ", terminator:".")

【讨论】:

  • appendNewline 的默认值为true
  • 在 iOS (9.0) 中,您需要使用terminator : "",例如print("...", terminator: "")
  • 你第一句话的说法不正确。 NSLog() 仍然有效,即使在最新的 Swift 2.x 中
【解决方案3】:

此外,Swift 2 有debugPrint()(和CustomDebugStringConvertible 协议)!

不要忘记debugPrint(),它的作用类似于print(),但most suitable for debugging

例子:

  • 字符串
    • print("Hello World!") 变为 Hello World
    • debugPrint("Hello World!") 变为 "Hello World"(引号!)
  • 范围
    • print(1..<6) 变为 1..<6
    • debugPrint(1..<6) 变为 Range(1..<6)

任何类都可以通过 CustomDebugStringConvertible 协议自定义其调试字符串表示。

【讨论】:

  • DebugPrintable 协议已重命名为 CustomDebugStringConvertible protocol
  • 所以 Swift 的 descriptiondebugDescription 就像 Python 的 strrepr
  • 是的,我想是的。
【解决方案4】:

还有另一种称为dump() 的方法也可用于记录:

func dump<T>(T, name: String?, indent: Int, maxDepth: Int, maxItems: Int)

使用其镜像将对象的内容转储到标准输出。

来自Swift Standard Library Functions

【讨论】:

    【解决方案5】:

    为了补充 Rob 的回答,自 iOS 10.0 以来,Apple 引入了一个全新的“统一日志记录”系统,该系统取代了现有的日志记录系统(包括 ASL 和 Syslog、NSLog),并且在性能上也超越了现有的日志记录方法,这要归功于它包括日志数据压缩和延迟数据收集在内的新技术。

    来自Apple

    统一的日志记录系统提供了一个单一的、高效的、高性能的 API,用于捕获跨系统所有级别的消息。这个统一的系统将日志数据集中存储在内存和磁盘上的数据存储中。

    Apple 强烈建议使用os_log 来记录各种消息,包括信息、调试、错误消息,因为与以前的日志系统相比,它的性能大大提高,并且它的集中数据收集允许方便的日志和活动检查开发商。事实上,新系统的占用空间可能非常小,不会导致“观察者效应”,即如果您插入日志记录命令,您的错误就会消失,从而干扰错误发生的时间。

    您可以通过here了解更多详情。

    总结一下:为方便起见,使用print() 进行个人调试(但在用户设备上部署时不会记录该消息)。然后,尽可能将统一日志记录 (os_log) 用于其他所有内容。

    【讨论】:

      【解决方案6】:

      iOS 记录器

      1. NSLog - 添加元信息(如时间戳和标识符)并允许您输出 1023 个符号。还将消息打印到控制台。最慢的方法。不安全,因为其他应用程序可以访问日志文件

        @import Foundation
        NSLog("SomeString")
        
      2. print - 将 all 字符串打印到 Xcode。比以前的性能更好

        @import Foundation
        print("SomeString")
        
      3. println(仅适用于 Swift v1)并在字符串末尾添加 \n

      4. os_log(来自 iOS v10)- 打印 32768 个符号 也打印到控制台。比以前的性能更好

        @import os.log
        os_log("SomeIntro: %@", log: .default, type: .info, "someString")
        
      5. Logger(来自 iOS v14)- 打印 32768 个符号 也打印到控制台。比以前的性能更好

        @import os
        let logger = Logger(subsystem: Bundle.main.bundleIdentifier!, category: "someCategory")
        logger.log("\(s)")
        

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2017-10-15
        • 2019-07-15
        • 1970-01-01
        • 2017-07-22
        • 2017-03-24
        • 1970-01-01
        • 2016-02-08
        • 2017-11-13
        相关资源
        最近更新 更多