Diagnose performance issues with the Xcode Organizer
Developer Tools 进阶 28m

使用 Xcode Organizer 诊断性能问题

Diagnose performance issues with the Xcode Organizer

2020年6月26日

在 Apple 官方观看视频

一句话判断

Xcode Organizer 不再只是看崩溃日志的地方,它现在能把线上用户的电池消耗、启动时间、挂死率(hang rate)等指标可视化呈现,是你从”我本地没问题”到”用户真的在骂”之间最短的验证路径。

这场 Session 讲了什么

Xcode 12 对 Organizer 做了一次全面升级。过去 Organizer 主要用来查看崩溃报告和 TestFlight 反馈,现在它集成了 MetricKit 采集到的聚合性能数据。你能在 Organizer 里直接看到 App 的电池使用情况、启动时间、内存指标、磁盘写入量以及 UI 挂死率,所有数据都按版本和设备类型分组展示。

Apple 强调的核心思路是”以用户为中心的性能监控”。传统做法是开发者在 Instruments 里跑 profile,但这只能代表你手里的设备。Organizer 把 MetricKit 收集的真实用户数据汇总后呈现给你,让你看到 95 分位、99 分位的性能表现——这些才是真实用户体验。Session 还介绍了如何结合 Xcode 的 Regressions 视图快速定位某个版本引入的性能退化。

值得深挖的点

MetricKit 与 Organizer 的数据闭环

MetricKit 在 iOS 13 引入,但当时数据只能通过 JSON payload 自己解析。Xcode 12 把这个流程打通了:你的 App 集成 MetricKit 后,用户设备会定期上报性能数据,Apple 服务器聚合后推送到 Xcode Organizer。关键在于,这个数据采集是完全匿名的,不会收集任何用户隐私信息。每个指标都有对应的维度切割——按操作系统版本、设备型号、App 版本——你可以精确定位”是 iPhone 7 上 iOS 14 的启动变慢了”还是”所有设备都受影响”。

Hang Rate 指标的实战价值

Hang rate 是这次新增的重要指标,它衡量的是主线程被阻塞导致用户感知到卡顿的比例。Apple 的定义是:如果主线程在 250ms 内没有响应,就算一次 hang。这个数值比传统的 FPS 监控更有意义,因为它直接对应用户的”卡住了”感受。如果你的 hang rate 超过 1%,就已经有相当比例的用户在忍受糟糕的体验了。

代码片段

集成 MetricKit 基础代码

场景:在 AppDelegate 中接收 MetricKit 的性能报告。

import MetricKit

// 在 AppDelegate 的 didFinishLaunching 中注册
func application(_ application: UIApplication,
                 didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
    MXMetricManager.shared.add(self)
    return true
}

// 接收每日聚合的指标数据
extension AppDelegate: MXMetricManagerSubscriber {
    func didReceive(_ payloads: [MXMetricPayload]) {
        for payload in payloads {
            // payload 包含电池、启动时间、内存、磁盘等聚合数据
            // 这些数据会自动同步到 Xcode Organizer
            let startTime = payload.hangTimeMetrics?.applicationHangTime
            print("应用挂死时间: \(String(describing: startTime))")
        }
    }
}

接收诊断数据(崩溃 + 挂死)

场景:处理 MetricKit 的诊断报告,包含具体堆栈信息。

// iOS 14 新增 MXDiagnosticPayload,可以收到崩溃和 hang 的诊断数据
func didReceive(_ payloads: [MXDiagnosticPayload]) {
    for payload in payloads {
        // 崩溃诊断
        if let crashDiagnostics = payload.crashDiagnostics {
            for diagnostic in crashDiagnostics {
                print("崩溃原因: \(diagnostic.exceptionCode ?? "未知")")
                // 包含完整的调用栈信息
            }
        }
        
        // 挂死诊断
        if let hangDiagnostics = payload.hangDiagnostics {
            for diagnostic in hangDiagnostics {
                print("挂死时长: \(diagnostic.hangDuration)")
            }
        }
    }
}

使用 MetricKit 设置自定义信号

场景:标记关键业务流程的性能区间。

import MetricKit

// 在关键操作前后打点(iOS 14 新增)
func performLogin() {
    let signpost = MXMetricManager.makeSignpostInterval()
    signpost.begin()
    
    // 执行登录网络请求...
    loginUser { result in
        signpost.end()
        // MetricKit 会自动收集这个区间的耗时
    }
}

最佳实践

已有项目:如果你已经在用 MetricKit,升级到 Xcode 12 后打开 Organizer 就能看到可视化数据。建议重点关注 hang rate 指标,如果某个版本 hang rate 突然升高,立刻用 Regressions 视图对比前后版本的差异。把 Organizer 的性能检查加入每次发版前的流程。

新项目:在第一天就集成 MetricKit,代码量很小。配合 XCTest 的 Metric 测试(参见 Session 10077),可以在 CI 里建立性能基线。线上看 Organizer,线下看 XCTest,形成完整的性能监控闭环。

还有什么值得关注

  • Organizer 现在支持按地区和设备型号过滤指标数据,方便定位特定环境的问题。
  • MetricKit 的诊断数据包含 call tree,可以直接在 Xcode 中打开,跳转到对应代码行。
  • Apple 建议将 MXMetricManager 的订阅放在 App 启动早期,确保不遗漏任何数据上报。
WWDC 2020