Swift: print() vs println() vs NSLog()

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

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

377985 次浏览

一些不同之处:

  1. print vs println:

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

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

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

  2. < p > # EYZ0:

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

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

    • NSLog在iOS 10-13/macOS 10.12-10。x使用# eyz1风格的格式字符串,例如

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

      这将产生:

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

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

    现在,虽然NSLog仍然可以工作,但我们通常会使用“统一日志记录”(见下文)而不是NSLog

  3. 有效的iOS 14/macOS 11,我们有Logger接口到“统一日志记录”系统。关于Logger的介绍,请参见WWDC 2020 在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 = <private>

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

      logger.log("url = \(url, privacy: .public)")
      
  4. 在iOS 14/macOS 11之前,iOS 10/macOS 10.12引入了os_log“统一日志记录”。关于统一登录的一般介绍,请参见WWDC 2016视频统一日志记录和活动跟踪

    • < p >进口# EYZ0:

      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)
      
    • 你也可以使用“Points of Interest”日志,如果你想从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)实现了同样的事情,但提供了更强大的功能。

当调试iOS应用程序时,必须在Xcode之外进行测试,统一日志记录的力量就会显现出来。例如,当测试后台iOS应用程序进程,如后台取回,连接到Xcode调试器改变应用的生命周期。所以,你经常会想在物理设备上测试,从设备本身运行应用,而不是从Xcode的调试器启动应用。统一的日志记录让您仍然可以从macOS控制台应用程序查看您的iOS设备日志语句。

如果使用斯威夫特2,现在只能使用print()向输出写入内容。

苹果将println ()print ()功能组合成 一。< / p >

更新至iOS 9

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

print("Hello Swift")

《终结者》

若要打印后面没有换行符的值,请传递一个空字符串作为结束符

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

分隔符

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

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

这两个

或者你可以这样结合使用

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

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

不要忘记debugPrint(),它的工作方式类似于print(),而不是最适合调试

例子:

  • < >强字符串
    • print("Hello World!")变成Hello World
    • debugPrint("Hello World!")变成"Hello World"(引用!)
    • 李< / ul > < / >
    • < >强范围
      • print(1..<6)变成1..<6
      • debugPrint(1..<6)变成Range(1..<6)
      • 李< / ul > < / >

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

还有另一个方法叫做dump(),也可以用来记录日志:

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

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

从# EYZ0

为了补充Rob的答案,自iOS 10.0以来,苹果推出了一个全新的“统一日志”系统,取代了现有的日志系统(包括ASL和Syslog, NSLog),并在性能上超越了现有的日志方法,这要归功于它的新技术,包括日志数据压缩和延迟数据收集。

从# EYZ0:

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

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

活动跟踪的性能,现在是新的统一日志系统的一部分

您可以在在这里中了解更多详细信息。

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

iOS记录器

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

    @import Foundation
    NSLog("SomeString")
    
  2. print -打印所有字符串到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 (from iOS v14) -打印32768年的象征也打印到控制台。表现比以前好吗

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