这是我想要做的一个例子:
func application(application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: NSError)
{
let nm = NetworkModel()
nm.sendlog("file name :AppDelegate , line number : 288", info: " Failed to register: \(error)")
}
Run Code Online (Sandbox Code Playgroud)
目前的情况下我做的是硬编码值line number
和file name
.但是有可能以编程方式选择line number
和file name
.
小智 104
Literal Type Value
#file String The name of the file in which it appears.
#line Int The line number on which it appears.
#column Int The column number in which it begins.
#function String The name of the declaration in which it appears.
#dsohandle String The dso handle.
Run Code Online (Sandbox Code Playgroud)
例
print("Function: \(#function), line: \(#line)")
Run Code Online (Sandbox Code Playgroud)
使用参数中的默认值,您还可以创建一个函数
public func track(_ message: String, file: String = #file, function: String = #function, line: Int = #line ) {
print("\(message) called from \(function) \(file):\(line)")
}
Run Code Online (Sandbox Code Playgroud)
可以像这样使用
track("enters app")
Run Code Online (Sandbox Code Playgroud)
在Swift 2.1中
Literal Type Value
__FILE__ String The name of the file in which it appears.
__LINE__ Int The line number on which it appears.
__COLUMN__ Int The column number in which it begins.
__FUNCTION__ String The name of the declaration in which it appears.
Run Code Online (Sandbox Code Playgroud)
有关详细信息,请参阅文档 检查文档
您可以使用#function
,#file
,#line
这是swift中log方法的实现:https://github.com/InderKumarRathore/SwiftLog
以下是片段
public func debugLog(object: Any, functionName: String = #function, fileName: String = #file, lineNumber: Int = #line) {
#if DEBUG
let className = (fileName as NSString).lastPathComponent
print("<\(className)> \(functionName) [#\(lineNumber)]| \(object)\n")
#endif
}
Run Code Online (Sandbox Code Playgroud)
对于swift 4和swift 5:
func printLog(_ message: String, file: String = #file, function: String = #function, line: Int = #line) {
#if DEVELOPMENT
let className = file.components(separatedBy: "/").last
print(" ? Error ----> File: \(className ?? ""), Function: \(function), Line: \(line), Message: \(message)")
#endif
}
// "? Error ----> File: classNameViewController.swift, function: functionName(), Line: 123, Message: messageError"
Run Code Online (Sandbox Code Playgroud)
import os.log\n\n@available(OSX 11.0, iOS 14.0, *)\nextension Logger {\n private static var subsystem = Bundle.main.bundleIdentifier!\n\n /// Logs the payment flows like Apple Pay.\n @available(OSX 11.0, iOS 14.0, *)\n static let payments = Logger(subsystem: subsystem, category: "payments")\n}\n\nstatic func DLog(message: StaticString, file: StaticString = #file, function: StaticString = #function, line: UInt = #line, column: UInt = #column, category: String, type: OSLogType = .info, bundle: Bundle = .main) {\n\n // This method is only for iOS 14+\n if #available(OSX 11.0, iOS 14.0, *) {\n\n Logger.payments.debug("\\(file) : \\(function) : \\(line) : \\(column) - \\(message, privacy: .private)")\n // This makes the message unreadable without a debugger attached.\n\n } else {\n // Fallback on earlier versions\n\n let customLog = OSLog(subsystem: bundle.bundleIdentifier!,\n category: category)\n\n // IMPORTANT: I have assumed here that you only print out non-sensitive data! Using %{private}@ or %{public}@ in an interpolated string is not portable to `Logger`!\n os_log(message, log: customLog, type: type)\n\n // Unfortunately this legacy API doesn\'t support non-StaticString logs. :(\n }\n}\n
Run Code Online (Sandbox Code Playgroud)\n请注意,您可能需要重新编写此代码,以便在私有/公共访问级别上获得更大的灵活性 -os_log
并且Logger
don\xe2\x80\x99t 以相同的方式处理隐私级别。这只是为了展示如果您不\xe2\x80\x99tos_log
在message
.
Apple建议使用操作系统日志记录,这就是我使用这种方法而不是print
语句的原因。我添加这个答案是因为Logger
iOS 14 中的新 API 也支持字符串插值。
我认为这里的答案解决了< iOS 14 的问题,但可以进一步提高内存效率,因为此调试日志记录功能可能会在 iOS 14+(新 API)的整个代码库中使用Logger
。苹果建议使用操作系统日志记录,这就是为什么我使用这种方法而不是print
语句(尽管这些仍然有效)。
这些都是微小的改进,但我认为它们会有所帮助,因为即使是微小的改进也会累积起来。事实上,Swift 标准库在任何可以使用的地方都使用了这些优化)!尽管Swift是一个高级别的语言,但这些优化是实现令人难以置信的内存效率的因素之一。语言(也是出色的 API 设计的一部分!),(-:
\n由于此功能可能非常适合作为通用(操作系统)日志记录服务的一部分,因此我还包含了在应用程序内进行日志记录时的注意事项。我认为这些可以在出于调试目的进行日志记录时对您有所帮助(我回答了这个问题,因为它可能是用于调试日志记录!)。
\nUInt
如果我知道情况Int
会是积极的,并且任何边缘情况崩溃都不太可能,我更喜欢在某些情况下使用。请注意,由于这个原因,我在与使用类型的类交互时不使用。这会在运行时分配更少的内存,而且我发现更具体也可以帮助我更好地理解代码。UInt
Foundation
Int
StaticString
我更喜欢在我知道字符串在编译时已知的地方使用。从文档来看,StaticString
仅提供对内容的低级访问String
并且是不可变的。因此仅在适当的情况下使用它。即使串联的字符串文字也不能用于初始化StaticString
. 因为它的功能比这更受限制,String
这意味着它是轻量级的——只需要一个地址指针和底层的长度。使用StaticString
还通过操作系统级内存管理提供了小幅性能提升,因为它既不分配也不释放(不需要引用计数)。Logger
API 进行日志记录比打印报表更好,原因有多种:性能、隐私和统一管理。它可以更好地调试已发布产品中的问题(操作系统日志提供更多上下文)。我建议StaticString
尽可能使用,例如函数和文件名,以及UInt
行号和列号。现在只有Logger
iOS 14+ API 才可以实现这一点。
我认为记录是一种平衡行为。如果您有权访问这些日志记录,那么在查看崩溃报告时,大量日志记录对于调试问题非常有帮助。但是,您需要平衡隐私、编译的二进制文件的大小和压倒日志系统。
\n1. 隐私:使用"\\(message, privacy: .private)"
和"\\(message, privacy: .public)"
来编辑敏感信息Logger
,并且在使用或语句时不要打印敏感信息。我建议在出于调试目的时将语句(用于生产)替换为操作系统日志。或者在日志服务中使用预处理器指令 ( )仅在一个方案上。NSLog
print
print
#if DEBUG
print
Debug
2. 编译后的二进制文件的大小:日志语句本质上是更多的代码行。添加的代码越多,二进制文件就越大。只要您不记录阳光下的所有内容,这通常不是问题,因为只有该指标的大幅增加才会影响二进制大小。
\n3. 日志系统不堪重负:如果日志记录过多,设备可能必须丢弃一些日志才能继续运行(由于操作系统多任务处理,运行时RAM 或交换空间有限- 对于旧设备来说情况更糟)。苹果通常可以可靠地处理大量用户日志记录,但在实践中很难实现这一点。不过,如果您确实遇到这种情况,一些更有用的日志事件可能会被推出窗口。
\n最重要的是要正确设置日志级别。默认情况下,iOS 上的日志条目.info
将在日志生成时被抑制,因此唯一真正的负面影响是二进制大小。如果您以( os_log) 或更高级别登录.log
.default
,则需要小心不要记录太多。Apple 的一般建议是您查看每个高级日志条目,以确保它们包含在调试时可能有用的信息。
最后,确保设置了subsystem和category。统一的日志系统处理大量的日志条目——带有类别的子系统让您更容易专注于具体问题。
\n这是一个非常固执己见的话题,所以我将重点关注我在做出决定时会想到的内容。YMMV:可能有更好的选择,如果有,请告诉我。
\n1. 按功能(特定于产品):例如,如果您是购物应用程序,则可以subsystem
按payment
或login
其他应用程序流程进行组织。如果您尚未使用模块化代码库来组织功能(或共享代码的框架),那么我可以推荐本教程系列。
2. 通过技术:我的意思是代码的领域,是推送通知、深层链接、用户默认(或持久性)逻辑。这可能对category
参数有帮助。
3. 按目标:如果可以的话,我也喜欢使用bundleIdentifier
当前的。如果您有扩展目标(推送通知)、多个目标或不同的平台(如 WatchOS、SiriKit 扩展等),这更有意义。您可以使用以下代码获取当前包:Bundle
subsystem
let myBundle = Bundle(for: MyClass.self)\n
Run Code Online (Sandbox Code Playgroud)\n请参阅此处了解详细演练 ( Access Device Console Logs
)。主要想法是将设备连接到您的 Mac(或使用 Mac 本身来运行 Mac 应用程序;)),打开Console.app
,运行应用程序并尝试重现崩溃。如果您一开始就做到了这一点,那么您可以将崩溃时间与日志相关联以获取更多上下文。
如果您是 Apple 的早期采用者,那么您就会知道某些 iOS Beta 版本的 bug 有多多;)。当向 Apple 发布错误报告时,操作系统日志会包含在sysdiagnose
文件中,因此您可能会获得更快的周转时间,因为您的错误报告噪音较少。
取决于你是否负担得起以及你是否真的需要它。我更喜欢最大限度地减少在代码中导入的第三方依赖项的数量(如果我可以控制这一点),并且本机 (Apple) 日志记录 API 对于我的大多数用例都工作得很好。这些服务每月额外收费,但优点是用户无法通过将设备连接到 Mac来查看日志(即使他愿意) 。Console.app
请注意,如果您应用日志级别,这不是问题,因此我通常不使用第三方服务(YMMV)。使用网络日志的一个潜在原因是,只要您相信第三方供应商可以防止数据泄露,就可以更安全地防止逆向工程(但它也不那么环保;))。.private