在 Xcode 12 / Swift 5.3 / iOS 14 中,您根本不必直接调用 os_log。相反,将您对 OSLog 类的使用替换为新的 Logger 类(import os 时可用)。这是一个例子:
let myLog = Logger(subsystem: "testing", category: "exploring")
然后,您可以直接在 Logger 对象上调用方法以使用该子系统和类别进行记录:
myLog.log("logging at \(#function)")
要在默认级别以外的级别登录,请使用该级别作为方法的名称:
myLog.debug("logging at \(#function)")
在消息字符串中,如你所见,Swift 字符串插值是合法的。对于带有description 的 Int、Double、Objective-C 对象和符合 CustomStringConvertible 的 Swift 对象,它是允许的。
这里 Swift 字符串插值的合法性令人惊讶,因为os_log 格式说明符的目的是推迟对参数的评估,将其推出您的应用程序(这样您的应用程序就不会通过记录减慢)并进入记录机制本身。嗯,惊喜!由于 Swift 5 中引入的自定义 Swift 字符串插值钩子,插值 被推迟了。
使用自定义字符串插值还有两个好处。首先,自定义字符串插值机制允许插值附带指定其行为的附加参数。这就是防止值被编辑的方式:
myLog.log("logging at \(#function, privacy: .public)")
您还可以使用其他参数来执行各种类型的字符串格式化,否则您必须使用 NSLog 格式说明符来执行,例如指定小数点后的位数以及其他类型的填充和对齐:
myLog.log("the number is \(i, format: .decimal(minDigits: 5))") // e.g. 00001
因此您再也不需要直接调用os_log,也不再需要使用NSLog-type 格式说明符。
iOS 13 及之前版本的旧答案:
马丁 R 的回答扩展了两点:
os_log("foo: %@ %@", log: .default, type: .debug, x, y.description)
type:参数可以省略,但log:参数不能省略;你必须拥有它,包括log: 标签,否则os_log 会误解你的意图。
此外,log: 值不必是 .default。通常会预先创建一个或多个 OSLog 对象,用作log: 参数的参数。这样做的好处是您可以为 OSLog 对象指定子系统和类别,而这些又允许您在 Xcode 控制台或控制台应用程序中过滤结果。
另外,关于 pkamb 的回答,如果我们知道我们的消息总是一个字符串,我们可以这样编写 OSLog 扩展(利用新的 Swift 5.2 callAsFunction 方法):
extension OSLog {
func callAsFunction(_ s: String) {
os_log("%{public}s", log: self, s)
}
}
结果是我们现在可以将我们的 OSLog 对象 myLog 本身视为一个函数:
myLog("The main view's bounds are \(self.view.bounds)")
这很好,因为它就像基本的print 语句一样简单。我很欣赏 WWDC 2016 警告不要进行这种预格式化,但如果这是您在 print 声明中已经在做的事情,我无法想象它会那么有害。