在IT技术中,print
、NSLog
和println
有什么区别?我应该在何时使用它们?
例如,在Python中如果我想打印一个字典,我只需使用print myDict
,但现在我有另外两个选项。我应该如何选择并使用它们?
几个区别:
print
和 println
:
print
函数在调试应用程序时会将消息打印到 Xcode 控制台中。
println
是其变体,在 Swift 2 中已被删除,不再使用。如果您看到旧代码正在使用 println
,现在可以安全地将其替换为 print
。
在 Swift 1.x 中,print
在打印字符串末尾没有添加换行符,而 println
则添加了。但是现在,print
始终在字符串末尾添加换行符。如果不想这样做,可以提供一个 terminator
参数,值为 ""
。
NSLog
:
NSLog
将时间戳和标识符添加到输出中,而 print
不会。
NSLog
语句出现在设备的控制台和调试器的控制台中,而 print
只出现在调试器控制台中。
iOS 10-13/macOS 10.12-10.x 中的 NSLog
使用类似于 printf
的格式字符串,例如:
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
。
从iOS 14 / macOS 11开始,我们有了Logger
界面来访问“统一日志记录”系统。有关Logger
的介绍,请参见WWDC2020 在Swift中探索日志记录。
要使用Logger
,必须导入os
:
import os
像 NSLog
一样,统一日志记录将输出消息到 Xcode 调试控制台和设备控制台。
创建一个 Logger
并记录一条消息:
let logger = Logger(subsystem: Bundle.main.bundleIdentifier!, category: "network")
logger.log("url = \(url)")
通过外部控制台应用程序观察应用程序时,您可以基于子系统(subsystem)
和类别(category)
进行筛选。这非常有用,以便将调试消息与(a)由其他子系统代表您的应用程序生成的那些消息,或者(b)来自其他类别或类型的消息区分开来。
您可以指定不同类型的日志记录消息,例如.info
、.debug
、.error
、.fault
、.critical
、.notice
、.trace
等:
logger.error("web service did not respond \(error.localizedDescription)")
如果使用外部控制台应用程序,则可以选择仅查看某些类别的消息(例如,如果在Console“操作”菜单上选择“包含调试消息”,则仅显示调试消息)。这些设置还决定许多微妙的问题详细信息,例如是否将事物记录到磁盘。有关更多详细信息,请参见WWDC视频。logger.log("url = \(url, privacy: .public)")
iOS 14/macOS 11之前,iOS 10/macOS 10.12推出了用于“统一日志记录”的os_log
。有关统一日志记录的介绍,请参见WWDC 2016视频Unified Logging and Activity Tracing。
导入 os.log
:
import os.log
你应该定义 subsystem
和 category
: 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
时,不能使用字符串插值。例如,使用print
和Logger
您可以这样做: logger.log("url = \(url)")
但是使用 os_log
,你需要这样做:
os_log("url = %@", url.absoluteString)
os_log
强制实施相同的数据隐私,但您可以在printf格式化程序中指定公共可见性(例如%{public}@
而不是%@
)。例如,如果您想从外部设备查看它,您必须执行以下操作:os_log("url = %{public}@", url.absoluteString)
您还可以使用“兴趣点”日志,如果您想查看从仪器中观察到的活动范围: 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://dev59.com/3mMk5IYBdhLWcg3wvARo#39416673。
总之,print
在Xcode中用于简单日志记录已足够,但统一日志记录(无论是使用Logger
还是os_log
)实现了相同的功能并提供了更强大的能力。
当调试iOS应用程序需要在Xcode之外测试时,统一日志记录的优势尤为突出。例如,在测试后台iOS应用进程(如后台获取)时,连接到Xcode调试器会改变应用生命周期。因此,您经常需要在物理设备上测试,从设备本身运行应用程序,而不是从Xcode的调试器启动应用程序。统一日志记录允许您仍然从macOS控制台应用程序监视iOS设备日志声明。
print
,它会显示在 Xcode 的调试区域中,就像 debugPrint
一样。唯一的区别是 print
最终会调用对象的 description
方法,而 debugPrint
则调用 debugDescription
,后者可能比 description
更冗长。 - Rob如果您正在使用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:".")
terminator:""
,例如print("...",terminator:"")
。 - Khotu NamdebugPrint()
(以及 CustomDebugStringConvertible
协议)!debugPrint()
,它的作用和 print()
相似,但更适合 调试。print("Hello World!")
变成 Hello World
debugPrint("Hello World!")
变成 "Hello World"
(有引号!)print(1..<6)
变成 1..<6
debugPrint(1..<6)
变成 Range(1..<6)
CustomDebugStringConvertible
协议自定义其调试字符串表示形式。description
相当于 debugDescription
,就像 Python 中的 str
相当于 repr
一样? - BallpointBenos_log
来记录各种消息,包括信息、调试、错误消息,因为相比之前的日志记录系统,它的性能得到了大幅度改进,并且其集中化数据收集使得开发人员可以方便地查看日志和活动。实际上,新系统可能是如此低的占用,以至于它不会导致“观察效应”,即如果您插入一个日志命令来干扰bug的定时发生,则bug会消失。
您可以在这里详细了解此内容。
总而言之:为方便个人调试,请使用print()
(但在部署到用户设备时不会记录消息)。然后,尽可能多地使用统一日志记录(os_log
)处理其他所有事项。
iOS记录器
NSLog
- 添加元信息(如时间戳和标识符),并允许输出1023个字符。同时将消息打印到控制台。这是最慢的方法。不安全,因为其他应用程序可以访问日志文件。
//@import Foundation //Objective-C
@import Foundation
NSLog("SomeString")
print
- 将所有字符串打印到Xcode。比前一种方法性能更好。
//@import Foundation //Objective-C
import Foundation
print("SomeString")
println
(仅适用于Swift v1)并在字符串末尾添加\n
。
os_log
(从iOS v10开始)- 打印32768个字符,同时打印到控制台。比前一种方法性能更好。
//@import os.log //Objective-C
@import os.log
os_log("SomeIntro: %@", log: .default, type: .info, "someString")
Logger
(从iOS v14开始)- 打印32768个字符,同时打印到控制台。比前一种方法性能更好。
//@import os //Objective-C
import os
let logger = Logger(subsystem: Bundle.main.bundleIdentifier!, category: "someCategory")
logger.log("some message \(Date)")
//some message <private>
//it is about privacy level
logger.log("some message \(Date, privacy: .public)")
//some message 2023-11-11 16:09:03 +0000
还有一种名为dump()
的方法也可用于日志记录:
func dump<T>(T, name: String?, indent: Int, maxDepth: Int, maxItems: Int)
Dumps an object’s contents using its mirror to standard output.
os_log
。请参见我的答案下面。 - HuaThamos_log
的Swift文档之外,也可以尝试查看Objective-C页面的完整文档,它更为详尽。 - mfaaniLogger
代替os_log
。 - Rob