Xcode 中的 Console 是 iOS 开发的调试工具,可实时显示 NSLog、print、os_log 的输出以及应用的崩溃日志。根据 Apple Unified Logging,自 iOS 10 起,Apple 建议使用 os_log 替代 NSLog,通过 Unified Logging System 集中收集消息。Console 将调试器输出和系统消息统一在 Debug Area 的单一窗口中,在开发的任何时刻均可访问。
要点
Console — Xcode 中 Debug Area 的一部分,位于编辑器底部面板(View → Debug Area → Activate Console,快捷键 Cmd + Shift + Y)。Console 显示正在运行的应用的所有文本输出:来自 NSLog、os_log、print 的消息、运行时警告以及应用崩溃时的自动异常转储。
Console 在模拟器和物理设备上均可工作。在模拟器上,消息通过本地管道即时到达;在设备上 — 通过 USB 连接,延迟 1-3 帧。对于生产应用,设备上的 Console 不可用 — 开发人员依赖 Crashlytics 或通过 log collect 远程收集的 Unified Logging。
与 Mac 上的系统应用 Console.app 不同,Xcode 中的 Console 窗口仅显示当前正在运行的应用的日志(可过滤)。Console.app 收集 Mac 上所有进程的日志,包括 iOS 模拟器。然而,对于 iOS 应用的调试,开发人员使用内置的 Xcode Console,因为它与 LLDB 调试器集成。
三个主要 API 可供 iOS 开发人员在 Console 中输出:NSLog(已过时)、os_log(推荐)和 print(仅 Swift)。每个在性能、格式化和与 Unified Logging System 兼容性方面都有自己的特点。
NSLog — 来自 Foundation 的函数,可在 Objective-C 和 Swift 中使用。NSLog 输出带有时间戳、进程名称和 PID 的消息。缺点:NSLog 同步写入系统缓冲区,在写入期间阻塞当前线程。在频繁调用时(例如在循环中),NSLog 会造成明显的延迟。Apple 不建议在新项目中使用 NSLog,但它仍然与旧代码和第三方库兼容。
os_log — 来自 os.framework 的 API,在 iOS 10 中引入。os_log 是异步的:消息被放入队列并写入缓冲区,不会阻塞调用线程。根据 WWDC 2016,os_log 在高负载场景中比 NSLog 快 50 倍。os_log 还支持动态管理:DEBUG 级别的消息仅在 Debug 构建中收集,在 Release 中忽略且没有性能开销。
print() — Swift 中最简单的输出方法。print 写入 stdout(标准输出),Xcode 将其重定向到 Console。print 不添加元数据(时间、级别),但支持 stdout 缓冲。对于快速调试,print 是一种方便的工具,但对于永久日志记录,它在功能和控制方面不如 os_log。
import os.log
// NSLog — 已过时,阻塞式
NSLog("Application started")
// os_log — 推荐,异步式
let log = OSLog(
subsystem: "com.myapp",
category: "lifecycle"
)
os_log("Application started", log: log)
// print — 快速 Swift 输出
print("Application started")
Unified Logging System (ULS) — Apple 全面的日志记录基础设施,在 iOS 10 和 macOS Sierra 中引入。ULS 将来自所有系统进程的消息收集到单一存储中,可通过 Mac 上的 log 命令行工具远程访问。开发人员使用 os_log 写入 ULS,使用 Console 读取。
每个 OSLog 由一对 subsystem(例如 com.myapp.network)和 category(例如 http、websocket)标识。子系统是应用的域(一个应用可以为不同模块有多个子系统)。类别是子系统内部的组件。subsystem + category 的组合允许在 Console 和 log collect 中灵活过滤日志。
| 级别 | OSLogType | 在 Console 中显示 | 在 Release 中收集 |
|---|---|---|---|
| Default | .default | 始终 | 是 |
| Info | .info | 当 os_log UI 启用时 | 是 |
| Debug | .debug | 仅在 Debug 构建中 | 否 |
| Error | .error | 始终带红色标签 | 是 |
| Fault | .fault | 始终带紫色标签 | 是 |
Mac 上的 log collect 命令从连接的 iOS 设备收集归档的日志到 .logarchive 文件。此文件可在 Mac 上的 Console.app 中打开进行详细分析,包括 os_log 消息、崩溃日志和系统诊断。要在设备上启用收集,需要启用开发者模式并通过 USB 连接设备。
使用 Console 的实际工作涉及三个主要场景:开发期间的活动日志记录、崩溃后的崩溃日志分析以及通过 .logarchive 进行的远程诊断。每个场景都有最佳的工具和设置组合。
建议为应用的每个模块创建单独的 OSLog,级别如下:debug(详细调试)、info(关键状态转换)、error(异常和故障)。在 Xcode Console 中,根据应用的子系统启用过滤器,以排除产生噪音并分散对应用逻辑注意力的系统消息。
当应用崩溃时,Xcode 自动停止执行并在 Console 中显示发生崩溃的线程,带有完整的堆栈跟踪。崩溃日志的第一行包含异常类型(NSException、EXC_BAD_ACCESS)和原因(reason)。从下往上研究堆栈跟踪:最后调用的方法是崩溃位置。对于加密地址(在 Release 中),需要通过 dSYM 进行符号化。
// OSLog 模块化配置示例
extension OSLog {
static let uiLifecycle = OSLog(
subsystem: "com.myapp.ui",
category: "lifecycle"
)
static let network = OSLog(
subsystem: "com.myapp.network",
category: "http"
)
static let database = OSLog(
subsystem: "com.myapp.data",
category: "core-data"
)
}
// 带级别的使用
os_log("View did load", log: .uiLifecycle, type: .debug)
os_log("HTTP 200 received", log: .network, type: .info)
os_log("Failed to save: \(error.localizedDescription)",
log: .database, type: .error)
Xcode Console 支持多个超出简单日志记录的高级功能。断点日志可以在 Console 中输出消息而无需停止执行,Debugger Command 中的 LLDB 命令可以完全控制输出的格式化。
您可以设置断点使其在 Console 中输出消息并自动继续执行。在所需行上放置断点,右键单击 → Edit Breakpoint → 添加 Debugger Command:“po self” 或 “expr @import UIKit” + Debugger Command:“po self.view”。选中 Automatically continue after evaluating。启动后,断点将在每次到达该行时在 Console 中显示命令结果,不会中断线程。
Xcode Console 支持在断点处停止时执行任意的 LLDB 命令。po(print object)输出对象描述,p(print)— 原始值,expr — 执行 Swift/ObjC 表达式。对于格式化输出,使用 p/CGRectGetWidth。LLDB 输出在到达断点后立即显示在 Console 中。
func processUserData(user: User) {
// 此处使用 Debugger Command 的断点:
// po "User name: \(user.name)"
// expr user.age = 30
print("Processing user: \(user.name)")
}
// 带顺序的自定义日志记录示例
func trackMethodCall(
file: String = #file,
function: String = #function
) {
os_log("[\(function)] called",
log: .uiLifecycle, type: .debug)
}
Xcode Console 与 Instruments(Xcode 的性能分析工具)紧密集成。通过 Product → Profile 使用 Logging 模板运行应用时,所有 os_log 消息都会记录到 Instruments 轨迹中并带有时间戳。这允许在同一时间线上同时查看日志、性能和系统事件,对于诊断竞态条件和性能回归至关重要。
常见问题
NSLog — 同步,阻塞线程,始终输出消息。os_log — 异步,在高负载场景中快 50 倍,支持类别和在 Release 构建中动态禁用调试级别而不损失性能。
检查日志级别:默认情况下,Console 只显示 default 及以上级别。要查看 info 和 debug,请在 Xcode Console 中打开 os_log 菜单并选择 Include Info Messages 和 Include Debug Messages,同时在方案设置中设置(Edit Scheme → Run → Arguments → OS_ACTIVITY_MODE = debug)。
选择 Console 中所需的消息,复制(Cmd + C)并粘贴到任何文本编辑器中。要完全转储,请使用终端命令:sudo log collect --device --output /tmp/app_logs.logarchive — 它会以结构化格式保存来自 iOS 设备的所有日志。
.default 和 .error 类型的 os_log 在 Release 中默认工作。要在 Release 中使用 .info 和 .debug,需要在 Xcode 方案中添加启动参数 -OSLogPreferencesApp “$(PRODUCT_BUNDLE_IDENTIFIER):debug”。如果没有此参数,debug 消息在 Release 中不会被收集,从而节省设备资源。
打开 Xcode 中的 Window → Organizer → Crashes。组织器显示从测试人员设备收集的所有崩溃日志,按异常类型分组。要进行符号化,需要来自发生崩溃的构建的 .dSYM 文件 — Xcode 会在存档可用时自动找到它。
总结
我们将开发一款交钥匙移动应用程序
IT Sectr自2017年以来为初创企业和企业打造iOS和Android应用程序。我们将为您提供咨询并提出最佳解决方案。