axiom-testflight-triage

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

TestFlight Crash & Feedback Triage

TestFlight崩溃与反馈处理流程

Overview

概述

Systematic workflow for investigating TestFlight crashes and reviewing beta feedback using Xcode Organizer. Core principle: Understand the crash before writing any fix — 15 minutes of triage prevents hours of debugging.
使用Xcode Organizer调查TestFlight崩溃并审核Beta版本反馈的系统化工作流。核心原则: 在编写任何修复之前先理解崩溃原因——15分钟的处理工作能避免数小时的调试。

Red Flags — Use This Skill When

适用场景

  • "A beta tester said my app crashed"
  • "I see crashes in App Store Connect metrics but don't know how to investigate"
  • "Crash logs in Organizer aren't symbolicated"
  • "User sent a screenshot of a crash but I can't reproduce it"
  • "App was killed but there's no crash — just disappeared"
  • "TestFlight feedback has screenshots I need to review"

  • "有Beta测试人员说我的应用崩溃了"
  • "我在App Store Connect指标中看到崩溃,但不知道如何调查"
  • "Organizer中的崩溃日志未被符号化"
  • "用户发送了崩溃截图,但我无法复现问题"
  • "应用直接消失了,没有崩溃报告"
  • "我需要审核TestFlight反馈中的截图"

Decision Tree — Start Here

决策树——从这里开始

"A user reported a crash"

"用户报告了崩溃"

  1. Open Xcode Organizer (Window → Organizer → Crashes tab)
  2. Select your app from the left sidebar
  3. Find the build version the user was running
  4. Is the crash symbolicated?
  5. Can you identify the crash location?
  1. 打开Xcode Organizer(窗口 → Organizer → 崩溃标签页)
  2. 从左侧边栏选择你的应用
  3. 找到用户正在使用的构建版本
  4. 崩溃日志是否已符号化?
  5. 你能确定崩溃位置吗?

"App was killed but no crash report"

"应用被终止但无崩溃报告"

Not all terminations produce crash reports. Check for:
  1. Jetsam reports — System killed app due to memory pressure
    • Organizer shows these separately from crashes
    • Look for high
      pageOuts
      value
  2. Watchdog termination — Main thread blocked too long
    • Exception code
      0x8badf00d
      ("ate bad food")
    • Happens during launch (>20s) or background tasks (>10s)
  3. MetricKit diagnostics — On-device termination reasons
    • Requires MetricKit integration in your app
并非所有终止都会生成崩溃报告,请检查以下情况:
  1. Jetsam报告 — 系统因内存压力终止应用
    • Organizer会将这些报告与崩溃分开显示
    • 查看较高的
      pageOuts
  2. Watchdog终止 — 主线程被阻塞时间过长
    • 异常代码
      0x8badf00d
      (谐音“ate bad food”)
    • 通常发生在启动阶段(超过20秒)或后台任务(超过10秒)
  3. MetricKit诊断信息 — 设备端的终止原因
    • 需要在应用中集成MetricKit

"I want to review TestFlight feedback"

"我想审核TestFlight反馈"

  1. Xcode Organizer → Feedback tab (next to Crashes)
  2. Or App Store Connect → My Apps → [App] → TestFlight → Feedback

  1. Xcode Organizer → 反馈标签页(崩溃标签页旁边)
  2. App Store Connect → 我的App → [你的应用] → TestFlight → 反馈

Xcode Organizer Walkthrough

Xcode Organizer操作指南

Opening the Organizer

打开Organizer

Window → Organizer (or ⌘⇧O from Xcode)
窗口 → Organizer(或在Xcode中使用快捷键⌘⇧O)

UI Layout

UI布局

┌─────────────────────────────────────────────────────────────────┐
│ [Toolbar: Time Period ▼] [Version ▼] [Product ▼] [Release ▼]   │
├──────────┬──────────────────────────┬───────────────────────────┤
│ Sidebar  │     Crashes List         │       Inspector           │
│          │                          │                           │
│ • Crashes│  ┌─────────────────────┐ │  Distribution Graph       │
│ • Energy │  │ syncFavorites crash │ │  ┌─────────────────────┐  │
│ • Hang   │  │ 21 devices • 7 today│ │  │ ▄ ▄▄▄ v2.0          │  │
│ • Disk   │  └─────────────────────┘ │  │ ▄▄▄▄▄ v2.0.1        │  │
│ Feedback │  ┌─────────────────────┐ │  └─────────────────────┘  │
│          │  │ Another crash...    │ │                           │
│          │  └─────────────────────┘ │  Device Distribution      │
│          │                          │  OS Distribution          │
│          ├──────────────────────────┤                           │
│          │     Log View             │  [Feedback Inspector]     │
│          │  (simplified crash view) │  Shows tester feedback    │
│          │                          │  for selected crash       │
└──────────┴──────────────────────────┴───────────────────────────┘
┌─────────────────────────────────────────────────────────────────┐
│ [工具栏: 时间范围 ▼] [版本 ▼] [产品 ▼] [发布渠道 ▼]   │
├──────────┬──────────────────────────┬───────────────────────────┤
│ 侧边栏  │     崩溃列表         │       检查器           │
│          │                          │                           │
│ • 崩溃│  ┌─────────────────────┐ │  分布图表       │
│ • 能耗 │  │ syncFavorites崩溃 │ │  ┌─────────────────────┐  │
│ • 卡顿   │  │ 21台设备 • 今日7次│ │  │ ▄ ▄▄▄ v2.0          │  │
│ • 磁盘   │  └─────────────────────┘ │  │ ▄▄▄▄▄ v2.0.1        │  │
│ 反馈 │  ┌─────────────────────┐ │  └─────────────────────┘  │
│          │  │ 另一个崩溃...    │ │                           │
│          │  └─────────────────────┘ │  设备分布      │
│          │                          │  系统版本分布          │
│          ├──────────────────────────┤                           │
│          │     日志视图             │  [反馈检查器]     │
│          │  (简化的崩溃视图) │  显示所选崩溃对应的测试人员反馈    │
│          │                          │                           │
└──────────┴──────────────────────────┴───────────────────────────┘

Key Features

核心功能

FeatureWhat It Does
Speedy DeliveryTestFlight crashes delivered moments after occurrence (not daily)
Year of HistoryFilter crashes by time period, see monthly trends
Product FilterFilter by App Clip, watch app, extensions, or main app
Version FilterDrill down to specific builds
Release FilterSeparate TestFlight vs App Store crashes
Share ButtonShare crash link with team members
Feedback InspectorSee tester comments for selected crash
功能说明
快速交付TestFlight崩溃会在发生后立即上报(而非每日汇总)
一年历史记录可按时间段筛选崩溃,查看月度趋势
产品筛选可按App Clip、手表应用、扩展或主应用筛选
版本筛选深入查看特定构建版本的崩溃情况
发布渠道筛选区分TestFlight和App Store的崩溃
分享按钮与团队成员分享崩溃链接
反馈检查器查看所选崩溃对应的测试人员评论

Crash Entry Badges

崩溃条目标识

Crashes in the list show badges indicating origin:
BadgeMeaning
App ClipCrash from your App Clip
WatchCrash from watchOS companion
ExtensionCrash from share extension, widget, etc.
(none)Main iOS app
崩溃列表中的标识会显示崩溃来源:
标识含义
App Clip来自App Clip的崩溃
Watch来自watchOS配套应用的崩溃
Extension来自分享扩展、小组件等的崩溃
无标识来自主iOS应用的崩溃

The Triage Questions Workflow

处理流程提问环节

Before diving into code, ask yourself these questions (from WWDC):
在深入代码之前,请先问自己以下问题(来自WWDC):

Question 1 — How Long Has This Been an Issue

问题1:这个问题存在多久了

→ Check the inspector's graph area on the right → Graph legend shows which versions are affected → Look for when the crash first appeared
→ 查看右侧检查器中的图表区域 → 图表图例显示受影响的版本 → 查看崩溃首次出现的时间

Question 2 — Is This Affecting Production or Just TestFlight

问题2:这会影响正式版还是仅影响TestFlight版本

→ Use the Release filter in toolbar → Select "Release" to see App Store crashes only → Select "TestFlight" for beta crashes only
→ 使用工具栏中的发布渠道筛选 → 选择"Release"仅查看App Store崩溃 → 选择"TestFlight"仅查看Beta版本崩溃

Question 3 — What Was the User Doing

问题3:用户当时在做什么

→ Open the Feedback Inspector (right panel) → Check for tester comments describing their actions → Context clues: network state, battery level, disk space
→ 打开反馈检查器(右侧面板) → 查看测试人员描述的操作 → 上下文线索:网络状态、电池电量、磁盘空间

Using the Feedback Inspector

使用反馈检查器

When a crash has associated TestFlight feedback, you'll see a feedback icon in the crashes list. Click it to open the Feedback Inspector.
Each feedback entry shows:
FieldWhy It Matters
Version/BuildConfirms exact build tester was running
Device modelDevice-specific crashes (older devices, specific screen sizes)
Battery levelLow battery can affect app behavior
Available diskLow disk can cause write failures
Network typeCellular vs WiFi, connectivity issues
Tester commentTheir description of what happened
Example insight from WWDC: A tester commented "I was going through a tunnel and hit the favorite button. A few seconds later, it crashed." This revealed a network timeout issue — the crash occurred because a 10-second timeout was too short for poor network conditions.
当崩溃关联了TestFlight反馈时,崩溃列表中会显示反馈图标。点击即可打开反馈检查器。
每个反馈条目包含:
字段重要性
版本/构建号确认测试人员使用的具体构建版本
设备型号特定设备的崩溃问题(旧设备、特定屏幕尺寸)
电池电量低电量会影响应用行为
可用磁盘空间磁盘空间不足会导致写入失败
网络类型蜂窝网络vs WiFi,连接问题
测试人员评论他们对问题的描述
WWDC示例洞察: 有测试人员评论"我在隧道里点击了收藏按钮,几秒后应用崩溃了"。这揭示了网络超时问题——崩溃是因为10秒的超时时间在网络条件差的情况下太短。

Opening Crash in Project

在项目中打开崩溃

  1. Select a crash in the list
  2. Click Open in Project button
  3. Xcode opens with:
    • Debug Navigator showing backtrace
    • Editor highlighting the exact crash line
  1. 在列表中选择一个崩溃
  2. 点击在项目中打开按钮
  3. Xcode会打开:
    • 显示调用栈的调试导航器
    • 编辑器高亮显示崩溃的具体代码行

Sharing Crashes

分享崩溃信息

  1. Select a crash
  2. Click Share button in toolbar
  3. Options:
    • Copy link to share with team
    • Add to your to-do list
  4. When teammate clicks link, Organizer opens focused on that specific crash

  1. 选择一个崩溃
  2. 点击工具栏中的分享按钮
  3. 选项:
    • 复制链接与团队成员分享
    • 添加到你的待办事项
  4. 当队友点击链接时,Organizer会直接打开该特定崩溃的详情

Symbolication Workflow

符号化工作流

Why Crashes Aren't Symbolicated

崩溃未被符号化的原因

Crash reports show raw memory addresses until matched with dSYM files (debug symbol files). Xcode handles this automatically when:
  • You archived the build in Xcode (not command-line only)
  • "Upload symbols to Apple" was enabled during distribution
  • The dSYM is indexed by Spotlight
崩溃报告会显示原始内存地址,直到与dSYM文件(调试符号文件)匹配。当满足以下条件时,Xcode会自动处理符号化:
  • 你使用Xcode归档了构建版本(而非仅使用命令行)
  • 分发时启用了"Upload symbols to Apple"
  • dSYM文件已被Spotlight索引

Quick Check: Is It Symbolicated?

快速检查:是否已符号化

In Organizer, look at the stack trace:
What You SeeStatus
0x0000000100abc123
Unsymbolicated — needs dSYM
MyApp.ViewController.viewDidLoad() + 45
Symbolicated — ready to analyze
System frames symbolicated, app frames notPartially symbolicated — missing your dSYM
在Organizer中查看调用栈:
显示内容状态
0x0000000100abc123
未符号化 — 需要dSYM文件
MyApp.ViewController.viewDidLoad() + 45
已符号化 — 可分析
系统框架已符号化,应用框架未符号化部分符号化 — 缺少你的dSYM文件

Manual Symbolication

手动符号化

If automatic symbolication failed:
bash
undefined
如果自动符号化失败:
bash
undefined

1. Find the crash's build UUID (shown in crash report header)

1. 查找崩溃的构建UUID(在崩溃报告头部显示)

Look for "Binary Images" section, find your app's UUID

查看"Binary Images"部分,找到你的应用UUID

2. Find matching dSYM

2. 查找匹配的dSYM文件

mdfind "com_apple_xcode_dsym_uuids == YOUR-UUID-HERE"
mdfind "com_apple_xcode_dsym_uuids == YOUR-UUID-HERE"

3. If not found, check Archives

3. 如果未找到,检查归档目录

ls ~/Library/Developer/Xcode/Archives/
ls ~/Library/Developer/Xcode/Archives/

4. Symbolicate a specific address

4. 对特定地址进行符号化

xcrun atos -arch arm64
-o MyApp.app.dSYM/Contents/Resources/DWARF/MyApp
-l 0x100000000
0x0000000100abc123
undefined
xcrun atos -arch arm64
-o MyApp.app.dSYM/Contents/Resources/DWARF/MyApp
-l 0x100000000
0x0000000100abc123
undefined

Common Symbolication Failures

常见符号化失败情况

SymptomCauseFix
System frames OK, app frames hexMissing dSYM for your appFind dSYM in Archives folder, or re-archive with symbols
Nothing symbolicatedUUID mismatch between crash and dSYMVerify UUIDs match; rebuild exact same commit
"No such file" from atosdSYM not in Spotlight indexRun
mdimport /path/to/MyApp.dSYM
Can't find dSYM anywhereArchived without symbolsEnable "Debug Information Format = DWARF with dSYM" in build settings
症状原因修复方案
系统框架正常,应用框架显示十六进制地址缺少应用的dSYM文件在归档目录中查找dSYM文件,或重新归档并包含符号
完全未符号化崩溃报告与dSYM文件的UUID不匹配验证UUID是否匹配;重新构建完全相同的提交版本
atos命令提示"No such file"dSYM文件未在Spotlight索引中运行
mdimport /path/to/MyApp.dSYM
完全找不到dSYM文件归档时未包含符号在构建设置中启用"Debug Information Format = DWARF with dSYM"

Preventing Symbolication Issues

避免符号化问题

bash
undefined
bash
undefined

Verify dSYM exists after archive

归档后验证dSYM文件是否存在

ls ~/Library/Developer/Xcode/Archives/YYYY-MM-DD/MyApp*.xcarchive/dSYMs/
ls ~/Library/Developer/Xcode/Archives/YYYY-MM-DD/MyApp*.xcarchive/dSYMs/

Verify UUID matches

验证UUID是否匹配

dwarfdump --uuid MyApp.app.dSYM

---
dwarfdump --uuid MyApp.app.dSYM

---

Reading the Crash Report

阅读崩溃报告

Key Fields (What Actually Matters)

关键字段(核心信息)

FieldWhat It Tells You
Exception TypeCategory of crash (EXC_BAD_ACCESS, EXC_CRASH, etc.)
Exception CodesSpecific error (KERN_INVALID_ADDRESS = null pointer)
Termination ReasonWhy the system killed the process
Crashed ThreadWhich thread died (Thread 0 = main thread)
Application Specific InformationOften contains the actual error message
Binary ImagesLoaded frameworks (helps identify third-party culprits)
字段说明
Exception Type崩溃类型(EXC_BAD_ACCESS、EXC_CRASH等)
Exception Codes具体错误代码(KERN_INVALID_ADDRESS = 空指针)
Termination Reason系统终止进程的原因
Crashed Thread崩溃的线程(Thread 0 = 主线程)
Application Specific Information通常包含实际错误消息
Binary Images已加载的框架(帮助识别第三方库问题)

Reading the Stack Trace

阅读调用栈

The crashed thread's stack trace reads top to bottom:
  • Frame 0 = Where the crash occurred (most specific)
  • Lower frames = What called it (call chain)
  • Look for your code = Frames with your app/framework name
Thread 0 Crashed:
0   libsystem_kernel.dylib    __pthread_kill + 8        ← System code
1   libsystem_pthread.dylib   pthread_kill + 288        ← System code
2   libsystem_c.dylib         abort + 128               ← System code
3   MyApp                     ViewController.loadData() ← YOUR CODE (start here)
4   MyApp                     ViewController.viewDidLoad()
5   UIKitCore                 -[UIViewController _loadView]
Start at frame 3 — the first frame in your code. Work down to understand the call chain.
崩溃线程的调用栈是从上到下读取的:
  • Frame 0 = 崩溃发生的位置(最具体)
  • 下方的帧 = 调用该代码的上层逻辑(调用链)
  • 寻找你的代码 = 包含你的应用/框架名称的帧
Thread 0 Crashed:
0   libsystem_kernel.dylib    __pthread_kill + 8        ← 系统代码
1   libsystem_pthread.dylib   pthread_kill + 288        ← 系统代码
2   libsystem_c.dylib         abort + 128               ← 系统代码
3   MyApp                     ViewController.loadData() ← 你的代码(从此处开始分析)
4   MyApp                     ViewController.viewDidLoad()
5   UIKitCore                 -[UIViewController _loadView]
从Frame 3开始分析 — 这是你的代码中的第一帧。向下查看以理解调用链。

Example: Interpreting a Real Crash

示例:解读真实崩溃报告

Exception Type:  EXC_BAD_ACCESS (SIGSEGV)
Exception Codes: KERN_INVALID_ADDRESS at 0x0000000000000010

Thread 0 Crashed:
0   MyApp    0x100abc123 UserManager.currentUser.getter + 45
1   MyApp    0x100abc456 ProfileViewController.viewDidLoad() + 123
2   UIKitCore 0x1a2b3c4d5 -[UIViewController loadView] + 89
Translation:
  • EXC_BAD_ACCESS
    with
    KERN_INVALID_ADDRESS
    = Tried to access invalid memory
  • Address
    0x10
    = Very low address, almost certainly nil dereference
  • Crashed in
    currentUser.getter
    = Accessing a property that was nil
  • Called from
    ProfileViewController.viewDidLoad()
    = During view setup
Likely cause: Force-unwrapping an optional that was nil, or accessing a deallocated object.

Exception Type:  EXC_BAD_ACCESS (SIGSEGV)
Exception Codes: KERN_INVALID_ADDRESS at 0x0000000000000010

Thread 0 Crashed:
0   MyApp    0x100abc123 UserManager.currentUser.getter + 45
1   MyApp    0x100abc456 ProfileViewController.viewDidLoad() + 123
2   UIKitCore 0x1a2b3c4d5 -[UIViewController loadView] + 89
解读:
  • EXC_BAD_ACCESS
    伴随
    KERN_INVALID_ADDRESS
    = 尝试访问无效内存
  • 地址
    0x10
    = 地址值极低,几乎可以肯定是空指针引用
  • currentUser.getter
    中崩溃 = 访问了一个为nil的属性
  • ProfileViewController.viewDidLoad()
    调用 = 在视图初始化阶段发生
可能原因: 强制解包了一个为nil的可选值,或访问了已释放的对象。

Common Crash Patterns

常见崩溃模式

EXC_BAD_ACCESS (SIGSEGV / SIGBUS)

EXC_BAD_ACCESS (SIGSEGV / SIGBUS)

What it means: Accessed memory that doesn't belong to you.
Common causes in Swift:
PatternExampleFix
Force-unwrap nil
user!.name
Use
guard let
or
if let
Deallocated objectAccessing
self
in escaped closure after dealloc
Use
[weak self]
Array out of bounds
array[index]
where index >= count
Check bounds first
Uninitialized pointerC interop with bad pointerValidate pointer before use
swift
// Before (crashes if user is nil)
let name = user!.name

// After (safe)
guard let user = user else {
    logger.warning("User was nil in ProfileViewController")
    return
}
let name = user.name
含义: 访问了不属于你的内存。
Swift中的常见原因:
模式示例修复方案
强制解包nil
user!.name
使用
guard let
if let
访问已释放对象在闭包逃逸后访问已释放的
self
使用
[weak self]
数组越界
array[index]
中index >= 数组长度
先检查边界
未初始化指针C语言交互时使用了无效指针使用前验证指针有效性
swift
// 修复前(当user为nil时会崩溃)
let name = user!.name

// 修复后(安全)
guard let user = user else {
    logger.warning("ProfileViewController中的User为nil")
    return
}
let name = user.name

EXC_CRASH (SIGABRT)

EXC_CRASH (SIGABRT)

What it means: App deliberately terminated itself.
Common causes:
PatternClue in Crash Report
fatalError()
/
preconditionFailure()
Your assertion message in Application Specific Info
Uncaught Objective-C exception
NSException
type and reason in report
Swift runtime error"Fatal error: ..." message
Deadlock detected
dispatch_sync
onto current queue
Debug tip: Look at "Application Specific Information" section — it usually contains the actual error message.
含义: 应用主动终止自己。
常见原因:
模式崩溃报告中的线索
fatalError()
/
preconditionFailure()
应用特定信息中包含你的断言消息
未捕获的Objective-C异常报告中包含
NSException
类型和原因
Swift运行时错误包含"Fatal error: ..."消息
检测到死锁
dispatch_sync
同步到当前队列
调试技巧: 查看"Application Specific Information"部分——通常包含实际错误消息。

Watchdog Termination (0x8badf00d)

Watchdog终止 (0x8badf00d)

What it means: Main thread was blocked too long and the system killed your app.
Time limits:
ContextLimit
App launch~20 seconds
Background task~10 seconds
App going to background~5 seconds
Common causes:
  • Synchronous network request on main thread
  • Synchronous file I/O on main thread
  • Deadlock between queues
  • Expensive computation blocking UI
swift
// Before (blocks main thread — will trigger watchdog)
let data = try Data(contentsOf: largeFileURL)
processData(data)

// After (offload to background)
Task.detached {
    let data = try Data(contentsOf: largeFileURL)
    await MainActor.run {
        self.processData(data)
    }
}
含义: 主线程被阻塞时间过长,系统终止了应用。
时间限制:
场景限制
应用启动~20秒
后台任务~10秒
应用进入后台~5秒
常见原因:
  • 在主线程执行同步网络请求
  • 在主线程执行同步文件I/O
  • 队列之间的死锁
  • 耗时计算阻塞UI
swift
// 修复前(阻塞主线程——会触发Watchdog)
let data = try Data(contentsOf: largeFileURL)
processData(data)

// 修复后(转移到后台线程)
Task.detached {
    let data = try Data(contentsOf: largeFileURL)
    await MainActor.run {
        self.processData(data)
    }
}

Jetsam (Memory Pressure Kill)

Jetsam(内存压力终止)

What it means: System terminated your app to free memory. No crash report — just gone.
Symptoms:
  • App "disappears" without any crash
  • Jetsam report in Organizer (separate from crashes)
  • High
    pageOuts
    value in report
  • Often happens during photo/video processing or large data operations
Investigation:
  1. Profile with Instruments → Allocations
  2. Look for memory spikes during the reported operation
  3. Check for image caching without size limits
  4. Look for large data structures kept in memory
Common fixes:
  • Use
    autoreleasepool
    for batch processing
  • Implement image cache with memory limits
  • Stream large files instead of loading entirely
  • Release references to large objects when backgrounded

含义: 系统为释放内存终止了应用。无崩溃报告——应用直接消失。
症状:
  • 应用"消失"但无任何崩溃报告
  • Organizer中有Jetsam报告(与崩溃分开显示)
  • 报告中
    pageOuts
    值较高
  • 通常发生在照片/视频处理或大数据操作期间
调查方法:
  1. 使用Instruments的Allocations工具分析
  2. 查看报告操作期间的内存峰值
  3. 检查是否有无限大小的图片缓存
  4. 检查是否有长时间保存在内存中的大数据结构
常见修复方案:
  • 批量处理时使用
    autoreleasepool
  • 实现带内存限制的图片缓存
  • 流式处理大文件而非一次性加载
  • 进入后台时释放大对象的引用

Terminations Without Crash Reports

无崩溃报告的终止情况

When users report "the app just closed" but you find no crash:
当用户报告"应用直接关闭了"但你找不到任何崩溃报告时:

The Terminations Organizer

终止情况Organizer

The Terminations Organizer (separate from Crashes) shows trends of app terminations that aren't programming crashes:
Window → Organizer → Terminations (in sidebar)
Termination CategoryWhat It Means
Launch timeoutApp took too long to launch
Memory limitHit system memory ceiling
CPU limit (background)Too much CPU while backgrounded
Background task timeoutBackground task exceeded time limit
Key insight: Compare termination rates against previous versions to find regressions. A spike in memory terminations after a release indicates a memory leak or increased footprint.
终止情况Organizer(与崩溃分开)显示非编程崩溃的应用终止趋势:
窗口 → Organizer → 终止情况(在侧边栏中)
终止类别含义
启动超时应用启动时间过长
内存限制达到系统内存上限
CPU限制(后台)后台时CPU占用过高
后台任务超时后台任务超过时间限制
关键洞察: 对比不同版本的终止率以找到回归问题。新版本发布后内存终止率飙升,表明存在内存泄漏或内存占用增加。

Check for Jetsam

检查Jetsam报告

  1. Organizer → Select app → Look for "Disk Write Diagnostics" or "Hang Diagnostics"
  2. These aren't crashes but system-initiated terminations
  1. Organizer → 选择应用 → 查看"磁盘写入诊断"或"卡顿诊断"
  2. 这些不是崩溃,而是系统发起的终止

Check for Background Termination

检查后台终止

Apps can be terminated in background for:
  • Memory pressure (jetsam)
  • CPU usage while backgrounded
  • Background task timeout
应用在后台可能因以下原因被终止:
  • 内存压力(Jetsam)
  • 后台CPU占用过高
  • 后台任务超时

Ask the User

询问用户

If no reports exist:
  1. "Was the app in the foreground when it closed?"
  2. "Did you see any error message?"
  3. "What were you doing right before it happened?"
  4. "How long had the app been open?"
如果没有相关报告:
  1. "应用关闭时是在前台吗?"
  2. "你看到任何错误提示了吗?"
  3. "发生前你正在做什么?"
  4. "应用已经打开多久了?"

Enable Better Diagnostics with MetricKit

使用MetricKit启用更好的诊断

MetricKit crash diagnostics are now delivered on the next app launch (not aggregated daily). This gives you faster access to crash data.
swift
import MetricKit

class MetricsManager: NSObject, MXMetricManagerSubscriber {

    static let shared = MetricsManager()

    func startListening() {
        MXMetricManager.shared.add(self)
    }

    func didReceive(_ payloads: [MXMetricPayload]) {
        // Process performance metrics
    }

    func didReceive(_ payloads: [MXDiagnosticPayload]) {
        for payload in payloads {
            // Crash diagnostics — delivered on next launch
            if let crashDiagnostics = payload.crashDiagnostics {
                for crash in crashDiagnostics {
                    // Process crash diagnostic
                    print("Crash: \(crash.callStackTree)")
                }
            }

            // Hang diagnostics
            if let hangDiagnostics = payload.hangDiagnostics {
                for hang in hangDiagnostics {
                    print("Hang duration: \(hang.hangDuration)")
                }
            }
        }
    }
}
When to use MetricKit vs Organizer:
Use CaseTool
Quick triage of TestFlight crashesOrganizer (faster, visual)
Programmatic crash analysisMetricKit
Custom crash reporting integrationMetricKit
Termination trends across versionsTerminations Organizer

MetricKit崩溃诊断现在会在应用下次启动时上报(而非每日汇总)。这能让你更快获取崩溃数据。
swift
import MetricKit

class MetricsManager: NSObject, MXMetricManagerSubscriber {

    static let shared = MetricsManager()

    func startListening() {
        MXMetricManager.shared.add(self)
    }

    func didReceive(_ payloads: [MXMetricPayload]) {
        // 处理性能指标
    }

    func didReceive(_ payloads: [MXDiagnosticPayload]) {
        for payload in payloads {
            // 崩溃诊断——下次启动时上报
            if let crashDiagnostics = payload.crashDiagnostics {
                for crash in crashDiagnostics {
                    // 处理崩溃诊断
                    print("Crash: \(crash.callStackTree)")
                }
            }

            // 卡顿诊断
            if let hangDiagnostics = payload.hangDiagnostics {
                for hang in hangDiagnostics {
                    print("Hang duration: \(hang.hangDuration)")
                }
            }
        }
    }
}
MetricKit与Organizer的适用场景对比:
场景工具
TestFlight崩溃快速处理Organizer(更快、可视化)
程序化崩溃分析MetricKit
自定义崩溃报告集成MetricKit
跨版本终止趋势分析终止情况Organizer

Claude-Assisted Interpretation

Claude辅助解读

Using the Crash Analyzer Agent

使用崩溃分析Agent

For automated crash analysis, use the crash-analyzer agent:
/axiom:analyze-crash
Or trigger naturally:
  • "Analyze this crash log"
  • "Parse this .ips file: ~/Library/Logs/DiagnosticReports/MyApp.ips"
  • "Why did my app crash? Here's the report..."
The agent will:
  1. Parse the crash report (JSON .ips or text .crash format)
  2. Check symbolication status
  3. Categorize by crash pattern (null pointer, Swift runtime, watchdog, jetsam, etc.)
  4. Generate actionable analysis with specific next steps
对于自动化崩溃分析,使用crash-analyzer Agent:
/axiom:analyze-crash
或自然触发:
  • "分析这个崩溃日志"
  • "解析这个.ips文件: ~/Library/Logs/DiagnosticReports/MyApp.ips"
  • "我的应用为什么崩溃了?这是报告..."
该Agent会:
  1. 解析崩溃报告(JSON .ips或文本 .crash格式)
  2. 检查符号化状态
  3. 按崩溃模式分类(空指针、Swift运行时、Watchdog、Jetsam等)
  4. 生成包含具体下一步操作的可执行分析结果

Effective Prompts

有效提示示例

Basic interpretation:
Here's a crash report from my iOS app. Help me understand:
1. What type of crash is this?
2. Where in my code did it crash?
3. What's the likely cause?

[paste full crash report]
With context (better results):
My TestFlight app crashed. Here's what I know:

- User was [describe action, e.g., "tapping the save button"]
- iOS version: [from crash report]
- Device: [from crash report]

Crash report:
[paste full crash report]

The relevant code is in [file/class name]. Help me understand the cause.
基础解读:
这是我的iOS应用的崩溃报告。帮我理解:
1. 这是什么类型的崩溃?
2. 崩溃发生在我的代码的哪个位置?
3. 可能的原因是什么?

[粘贴完整崩溃报告]
带上下文(效果更好):
我的TestFlight应用崩溃了。我已知的信息:

- 用户当时正在[描述操作,例如"点击保存按钮"]
- iOS版本:[来自崩溃报告]
- 设备:[来自崩溃报告]

崩溃报告:
[粘贴完整崩溃报告]

相关代码在[文件/类名]中。帮我分析原因。

What to Include

需要包含的信息

IncludeWhy
Full crash reportPartial reports lose context
What user was doingHelps narrow down code paths
Relevant code snippetsIf you know the crash area
iOS version and deviceSome crashes are device/OS specific
内容原因
完整崩溃报告部分报告会丢失上下文
用户操作帮助缩小代码路径范围
相关代码片段如果你知道崩溃大致区域
iOS版本和设备部分崩溃是特定设备/系统版本的问题

What Claude Can Help With

Claude能提供的帮助

  • Interpreting exception types and codes
  • Identifying likely cause from stack trace
  • Explaining unfamiliar system frames
  • Suggesting where to add logging
  • Proposing fix patterns
  • 解读异常类型和代码
  • 从调用栈识别可能的原因
  • 解释不熟悉的系统帧
  • 建议添加日志的位置
  • 提出修复模式

What Requires Your Judgment

需要你判断的内容

  • Whether the suggested fix is correct for your architecture
  • How to reproduce the crash locally
  • Priority relative to other bugs
  • Whether it's a regression or long-standing issue

  • 建议的修复是否适合你的架构
  • 如何在本地复现崩溃
  • 相对于其他Bug的优先级
  • 这是回归问题还是长期存在的问题

Feedback Triage Workflow

反馈处理工作流

Where to Find Feedback

反馈位置

Xcode Organizer (recommended): Window → Organizer → Select app → Feedback tab
App Store Connect: My Apps → [App] → TestFlight → Feedback
Xcode Organizer(推荐): 窗口 → Organizer → 选择应用 → 反馈标签页
App Store Connect: 我的App → [你的应用] → TestFlight → 反馈

What's in Each Feedback Entry

每个反馈条目包含的内容

ComponentDescription
ScreenshotWhat the user saw (often the most valuable part)
Text commentUser's description of the issue
Device/OSiPhone model and iOS version
App versionWhich TestFlight build
TimestampWhen submitted
组件描述
截图用户看到的内容(通常是最有价值的部分)
文字评论用户对问题的描述
设备/系统版本iPhone型号和iOS版本
应用版本对应的TestFlight构建版本
时间戳提交时间

Triage Workflow

处理工作流

  1. Sort by recency — Newest first, unless investigating specific issue
  2. Scan screenshots — Visual issues are immediately apparent
  3. Read comments — User's description and context
  4. Check version — Is this fixed in a newer build?
  5. Categorize:
CategoryAction
🐛 BugInvestigate, file issue, prioritize fix
💡 Feature requestAdd to backlog if valuable
UnclearCan't act without more context
Working as intendedMay indicate UX confusion
  1. 按时间排序 — 最新的优先,除非正在调查特定问题
  2. 扫描截图 — 视觉问题能立即识别
  3. 阅读评论 — 用户的描述和上下文
  4. 检查版本 — 新版本中是否已修复?
  5. 分类:
分类操作
🐛 Bug调查、创建Issue、确定修复优先级
💡 功能请求如果有价值则添加到待办列表
不明确缺少更多上下文无法处理
符合预期可能表明存在UX混淆

Limitations

局限性

  • No direct reply — TestFlight doesn't support responding to feedback
  • Screenshots only — No video recordings
  • Limited context — Users often don't explain what they were trying to do
  • 无法直接回复 — TestFlight不支持回复反馈
  • 仅支持截图 — 不支持视频录制
  • 上下文有限 — 用户通常不会解释他们的操作意图

Getting More Context

获取更多上下文

If feedback is unclear and the tester is reachable:
  • Contact through TestFlight group email
  • Add in-app feedback mechanism with more detail capture
  • Include reproduction steps prompt in your TestFlight notes

如果反馈不明确且能联系到测试人员:
  • 通过TestFlight群组邮件联系
  • 添加应用内反馈机制以收集更多细节
  • 在TestFlight说明中提示用户提供复现步骤

Pressure Scenarios

压力场景

Scenario 1: "VIP user says app crashes constantly, but I can't find any crash reports"

场景1:"重要用户说应用经常崩溃,但我找不到任何崩溃报告"

Pressure: Important stakeholder, no evidence, tempted to dismiss with "works for me"
Correct approach:
  1. Verify they're on TestFlight (not App Store, not dev build)
  2. Confirm they've consented to share diagnostics (Settings → Privacy → Analytics)
  3. Check for jetsam reports (kills without crash reports)
  4. Check crash reports for their specific device/OS combination
  5. Ask for specific reproduction steps
  6. If still nothing: request screen recording of the issue
Response template:
"I've checked our crash reports and don't see crashes matching your description yet. To help investigate: (1) Could you confirm you're running the TestFlight version? (2) What exactly happens — does the app close suddenly, freeze, or show an error? (3) What were you doing right before? This will help me find the issue."
Why this matters: "Works for me" destroys trust. Investigate thoroughly before dismissing.
压力: 重要利益相关者,无证据,容易想用"我这里正常"来敷衍
正确做法:
  1. 确认他们使用的是TestFlight版本(而非App Store或开发版本)
  2. 确认他们已同意共享诊断信息(设置 → 隐私与安全性 → 分析与改进)
  3. 检查Jetsam报告(无崩溃报告的终止)
  4. 检查他们特定设备/系统版本的崩溃报告
  5. 询问具体的复现步骤
  6. 如果仍无结果:请求问题的屏幕录制
回复模板:
"我已检查了崩溃报告,目前未找到符合你描述的崩溃。为了帮助调查:(1) 能否确认你使用的是TestFlight版本?(2) 具体是什么情况——应用是突然关闭、卡顿还是显示错误?(3) 发生前你正在做什么?这些信息能帮我找到问题。"
重要性: "我这里正常"会破坏信任。在敷衍之前一定要彻底调查。

Scenario 2: "Crash rate spiked after latest TestFlight build, need to fix ASAP"

场景2:"最新TestFlight版本发布后崩溃率飙升,需要立即修复"

Pressure: Time pressure, tempted to guess at fix based on code changes
Correct approach:
  1. Open Organizer → Crashes → Filter to the new build
  2. Group crashes by exception type (look for the dominant signature)
  3. Identify the #1 crash by frequency
  4. Symbolicate and read the crash report fully
  5. Understand the cause before writing any fix
  6. If possible, reproduce locally
  7. Fix the verified cause, not a guess
Why this matters: Rushed guesses often introduce new bugs or miss the real issue. 15 minutes of proper triage prevents hours of misdirected debugging.
压力: 时间紧迫,容易想根据代码改动猜测修复方案
正确做法:
  1. 打开Organizer → 崩溃 → 筛选到新版本
  2. 按异常类型分组崩溃(寻找占比最高的崩溃类型)
  3. 确定出现频率最高的头号崩溃
  4. 符号化并完整阅读崩溃报告
  5. 先理解原因再编写修复
  6. 如果可能,在本地复现
  7. 修复已确认的原因,而非猜测
重要性: 仓促的猜测往往会引入新Bug或错过真正的问题。15分钟的正确处理能避免数小时的无效调试。

Scenario 3: "Crash report is symbolicated but I still don't understand it"

场景3:"崩溃报告已符号化但我还是看不懂"

Pressure: Tempted to ignore it or make random changes hoping it helps
Correct approach:
  1. Paste full crash report into Claude with context
  2. Ask for interpretation, not just "fix this"
  3. Research exception type if unfamiliar
  4. If still unclear after research, add logging around the crash site:
swift
func suspectFunction() {
    logger.debug("Entering suspectFunction, state: \(debugDescription)")
    defer { logger.debug("Exiting suspectFunction") }

    // ... existing code ...
}
  1. Ship instrumented build to TestFlight
  2. Wait for reproduction with better context
Why this matters: Understanding beats guessing. Logging beats speculation. It's okay to say "I need more information" rather than shipping a random change.

压力: 容易想忽略或随机修改代码碰运气
正确做法:
  1. 将完整崩溃报告和上下文粘贴到Claude中
  2. 请求解读,而非直接要求"修复这个"
  3. 研究不熟悉的异常类型
  4. 如果研究后仍不清楚,在崩溃位置附近添加日志:
swift
func suspectFunction() {
    logger.debug("进入suspectFunction,状态:\(debugDescription)")
    defer { logger.debug("退出suspectFunction") }

    // ... 现有代码 ...
}
  1. 发布带日志的版本到TestFlight
  2. 等待包含更多上下文的复现报告
重要性: 理解比猜测更重要。日志比碰运气更可靠。与其随机修改代码,不如说"我需要更多信息"。

Quick Reference

快速参考

Organizer Keyboard Shortcuts

Organizer快捷键

ActionShortcut
Open Organizer⌘⇧O (from Xcode)
Refresh⌘R
操作快捷键
打开Organizer⌘⇧O(在Xcode中)
刷新⌘R

Common Exception Codes

常见异常代码

CodeMeaning
KERN_INVALID_ADDRESS
Null pointer / bad memory access
KERN_PROTECTION_FAILURE
Memory protection violation
0x8badf00d
Watchdog timeout (main thread blocked)
0xdead10cc
Deadlock detected
0xc00010ff
Thermal event (device too hot)
代码含义
KERN_INVALID_ADDRESS
空指针/无效内存访问
KERN_PROTECTION_FAILURE
内存保护违规
0x8badf00d
Watchdog超时(主线程阻塞)
0xdead10cc
检测到死锁
0xc00010ff
过热事件(设备温度过高)

Crash Report Sections

崩溃报告部分

SectionContains
HeaderApp info, device, OS, date
Exception InformationCrash type and codes
Termination ReasonWhy system killed the process
Triggered by ThreadWhich thread crashed
Application SpecificError messages, assertions
Thread BacktracesStack traces for all threads
Binary ImagesLoaded frameworks and addresses

部分包含内容
头部应用信息、设备、系统版本、日期
异常信息崩溃类型和代码
终止原因系统终止进程的原因
崩溃线程崩溃的线程
应用特定信息错误消息、断言
线程调用栈所有线程的调用栈
二进制镜像已加载的框架和地址

Resources

参考资源

WWDC: 2018-414, 2020-10076, 2020-10078, 2020-10081, 2021-10203, 2021-10258
Docs: /xcode/diagnosing-issues-using-crash-reports-and-device-logs, /xcode/examining-the-fields-in-a-crash-report, /xcode/adding-identifiable-symbol-names-to-a-crash-report, /xcode/identifying-the-cause-of-common-crashes, /xcode/identifying-high-memory-use-with-jetsam-event-reports
Skills: axiom-memory-debugging, axiom-xcode-debugging, axiom-swift-concurrency
Agents: crash-analyzer (automated crash log parsing and analysis)
WWDC: 2018-414, 2020-10076, 2020-10078, 2020-10081, 2021-10203, 2021-10258
文档: /xcode/diagnosing-issues-using-crash-reports-and-device-logs, /xcode/examining-the-fields-in-a-crash-report, /xcode/adding-identifiable-symbol-names-to-a-crash-report, /xcode/identifying-the-cause-of-common-crashes, /xcode/identifying-high-memory-use-with-jetsam-event-reports
技能: axiom-memory-debugging, axiom-xcode-debugging, axiom-swift-concurrency
Agent: crash-analyzer(自动化崩溃日志解析与分析)