📋 目录
- 一、概述与历史演进
- 二、核心概念与崩溃报告结构
- 三、崩溃报告格式:.crash 与 .ips
- 四、dSYM 与符号化原理
- 五、获取崩溃报告
- 六、符号化操作 SOP
- 七、异常类型与诊断要点
- 八、崩溃分析流程与解读
- 九、关键概念图示与流程
- 十、伪代码与算法说明
- 十一、应用场景与最佳实践
- 参考文献
一、概述与历史演进
1.1 什么是崩溃日志与符号化
当 iOS/macOS 应用因未捕获异常、非法内存访问、系统终止等原因退出时,操作系统会生成一份崩溃报告(crash report),记录进程终止时的状态:异常类型、终止原因、各线程的调用栈(backtrace)、已加载的二进制镜像(binary images)等 [1][2]。其中调用栈以内存地址形式呈现;符号化(symbolication) 即把这些地址替换为可读的函数名与源码行号,使开发者能定位到具体代码位置 [2][3]。
- 未符号化:栈帧显示为
0x1022cbfa8、0x1022c0000 + 49064等,难以直接对应源码。 - 已符号化:栈帧显示为
Line.updateRectForExistingPoint(_:) (in TouchCanvas) + 656、ViewController.touchesEstimatedPropertiesUpdated(_:) (in TouchCanvas) + 304,可直接对应到工程中的类与方法 [2]。
符号化依赖与崩溃时运行二进制一一对应的 dSYM(Debug Symbol)文件及正确的加载地址(load address);只有 Build UUID 一致 的二进制与 dSYM 才能正确反解 [3][4]。
1.2 历史与格式演进
| 时期/变化 | 说明 |
|---|---|
| 传统 .crash 文本格式 | 早期至 iOS 14,崩溃报告多为纯文本:Incident Identifier、Process、Exception Type、Thread 0 Crashed、Binary Images 等字段,便于人工阅读与 grep [1][5] |
| iOS 15 / macOS 12 起 .ips | 系统改为将崩溃数据存为 JSON,文件扩展名为 .ips;首行为 IPS 元数据对象,其余为崩溃报告数据对象。Console 等工具将 JSON 转成可读展示 [6][7] |
| Xcode Organizer 与自动符号化 | 从 App Store / TestFlight 收集的崩溃若在上传时包含符号,Xcode 的 Crashes 组织器可自动符号化;本地需自行提供 dSYM [2][8] |
| TN2151 与现行文档 | Apple 早年的 Technical Note TN2151: Understanding and Analyzing Application Crash Reports 仍被广泛引用;现行说明已迁移至 Adding identifiable symbol names to a crash report 等官方文档 [2][3] |
1.3 典型应用场景
- 线上/TestFlight 崩溃定位:用户或测试反馈崩溃,从 Xcode Organizer 或邮件拿到 .ips/.crash,用对应版本的 dSYM 符号化后根据异常类型与栈顶帧排查。
- 内存与稳定性问题:EXC_BAD_ACCESS、EXC_CRASH (SIGABRT)、Watchdog 等,结合 Exception Type、Termination Reason、Last Exception Backtrace 分析。
- 审核或论坛反馈:App Review 或用户提供的 .txt/.crash,重命名为 .crash 后在 Xcode 中拖入 Device Logs 或使用 symbolicatecrash/atos 反解 [2][8]。
- 多版本/多架构管理:为每个分发版本保留 Archive 与 dSYM,用 UUID 匹配正确 dSYM 进行符号化 [3][4]。
二、核心概念与崩溃报告结构
2.1 崩溃报告包含哪些信息
无论 .crash 文本还是 .ips 中的 JSON,一份完整崩溃报告通常包含 [1][6][9]:
| 部分 | 含义 |
|---|---|
| Header / 元数据 | 进程名、Bundle ID、版本、设备/系统、时间、Incident Identifier、CrashReporter Key 等,用于区分环境与用户 |
| Exception / 异常信息 | 异常类型(如 EXC_BAD_ACCESS、EXC_BREAKPOINT、EXC_CRASH)、信号(SIGSEGV、SIGABRT 等)、Exception Codes、Exception Message/Subtype |
| Termination | 若进程被系统或其它进程终止,会包含 Termination Reason、namespace、code、indicator 等 [6] |
| Threads / 线程与栈 | 各线程的 backtrace(frames)、触发崩溃的线程标记、部分场景下的 threadState(寄存器) |
| Last Exception Backtrace | 语言层异常(如 Objective-C/Swift 未捕获异常)时的专用栈,便于区分“谁抛出了异常” [9] |
| Binary Images | 进程内已加载的二进制列表:名称、路径、UUID、加载地址(base)、大小;符号化与 atos 依赖此处的 UUID 与 base |
2.2 栈帧(Frame)与 Backtrace
- Frame 0:崩溃发生时正在执行的函数(或最内层调用)。
- Frame 1, 2, …:调用者链,从内到外;通常从栈顶向下读,先看 Frame 0 与自家 App 的帧,再结合系统帧理解调用链 [9]。
- 每帧包含:二进制名、运行时地址(或 imageOffset + 对应 image 的 base)、符号化后为 函数名 + 偏移(+ 行号视工具而定) [6][7]。
三、崩溃报告格式:.crash 与 .ips
3.1 传统 .crash 文本格式(概要)
常见字段包括 [1][5]:
Incident Identifier、CrashReporter KeyProcess、Identifier、Version、Code TypeException Type、Exception Codes、Exception Subtype、Crashed ThreadThread 0 Crashed:下列出各帧:序号 二进制名 地址 符号或 基址+偏移Binary Images:下列出各镜像的地址范围、名称、UUID(括号内,常为小写无连字符)
Xcode 的 Device Logs 要求文件扩展名为 .crash;若拿到的是 .txt 或其它扩展名,需重命名为 .crash 再拖入,才能正确触发符号化 [2]。
3.2 .ips:JSON 双对象结构(iOS 15+)
.ips 文件由两段 JSON 组成 [6][7]:
- 第一行:IPS 元数据对象(单行一个 JSON 对象)。
- 其余内容:崩溃报告数据对象(当
bug_type == "309"时表示崩溃报告)。
解析逻辑要点(与官方示例一致)[6]:
- 先读第一行解析 metadata。
- 若
metadata["bug_type"] == "309",再把剩余部分解析为 report。 - 报告中的地址、码值等在 JSON 中多为十进制,需按需转为十六进制以便阅读或传给 atos [6][7]。
3.2.1 IPS 元数据常用键
| Key | 类型 | 说明 |
|---|---|---|
name | String | 进程可执行文件名 |
bug_type | String | 日志类型,309 表示崩溃报告;288 表示 stackshot 等 [6] |
bundleID | String | Bundle 标识符 |
build_version | String | 构建版本号 |
incident_id | String | 报告唯一 ID |
platform | Number | 平台(1=macOS, 2=iOS, 3=tvOS, 4=watchOS, 6=Mac Catalyst, 7=iOS Simulator 等)[6] |
timestamp | String | 日志系统记录时间 |
3.2.2 崩溃报告对象常用键
| Key | 类型 | 说明 |
|---|---|---|
exception | Dictionary | type、signal、codes、subtype、message 等 [6] |
faultingThread | Number | 崩溃线程在 threads 数组中的下标 |
threads | Array | 各线程对象,含 frames、id、queue、triggered、threadState 等 [6][7] |
usedImages | Array | Binary images:base、size、name、path、uuid、arch、source 等 [7] |
captureTime、procLaunch | String | 崩溃时间、进程启动时间 |
lastExceptionBacktrace | Array | 语言层异常栈 [6] |
bundleInfo、osVersion、storeInfo | Dictionary | 包信息、系统版本、商店信息等 |
3.2.3 Frames 与 Binary Images(用于符号化)
- frames 中每帧:
imageIndex(对应 usedImages 下标)、imageOffset(相对该镜像的偏移)、symbol、symbolLocation(符号化后才有)[7]。 - usedImages 中每项:
base(加载地址)、uuid(Build UUID,用于匹配 dSYM)、name、path、arch[7]。
符号化时:运行时地址 = base + imageOffset;atos 需要 -l base 和该镜像对应的 dSYM [2][3]。
四、dSYM 与符号化原理
4.1 dSYM 是什么
dSYM(Debug Symbol File) 是 Xcode 生成的调试符号包,与编译出的二进制一一对应:包含函数名、行号、变量等 DWARF 调试信息,不随 App 分发,仅用于调试与崩溃反解 [3][4]。每个可执行体(主程序、Extension、Framework)各有自己的 dSYM;二进制与 dSYM 通过 Build UUID 绑定,只有 UUID 完全一致才能正确符号化 [3][4]。
4.2 生成与归档 dSYM
在 Xcode 中 [4]:
- Build Settings → Debug Information Format 设为 DWARF with dSYM File(Release 与需分析崩溃的构建建议一致)。
- Generate Debug Symbols 建议保持 YES。
归档(Archive)时,Xcode 会把该次构建的所有二进制与 dSYM 收进 .xcarchive;上传 App Store/TestFlight 时可勾选上传符号,便于在 Crashes 组织器中自动符号化 [2][4]。必须为每个对外分发的版本保留对应 Archive,否则无法为该版本崩溃找到匹配 dSYM [4]。
4.3 符号化的本质
- 崩溃报告里记录的是运行时地址(或 image 的 base + offset)。
- 编译器在生成二进制时,会把符号与地址的对应关系写入 dSYM(DWARF)。
- 符号化工具(Xcode、symbolicatecrash、atos)根据 UUID 找到对应 dSYM,再根据 load address(base) 把运行时地址换算成“镜像内偏移”,在 dSYM 中查找函数与行号并写回报告或输出 [2][3]。
因此:UUID 不一致(例如换了 Xcode 版本或编译选项重新构建)、缺少 dSYM 或 load address 错误,都会导致无法符号化或结果错误。
五、获取崩溃报告
5.1 从 Xcode 与 App Store Connect
- Xcode → Window → Organizer → Crashes:可看到已同步的崩溃报告(来自 TestFlight/App Store 用户且已开启诊断共享)。若上传时包含符号,此处多为已符号化 [2][8]。
- Xcode → Window → Devices and Simulators → 选中设备 → View Device Logs:可把本机或用户导出的 .crash/.ips 拖入 Device Logs 列表,由 Xcode 自动尝试符号化(需本机有对应 dSYM 或系统符号)[2]。
5.2 从设备本地导出(用户/测试人员操作)
iOS / iPadOS [8]:
- 设置 → 隐私与安全性 → 分析与改进 → 分析数据(Analytics Data)。
- 找到以应用名为前缀的崩溃日志(名称常以
_开头),点进后通过“分享”以邮件等方式发给开发者。
macOS [8]:
- 打开 Console.app → 左侧选择本机 → Crash Reports。
- 找到对应应用的崩溃报告,右键 → Reveal in Finder,可复制或通过邮件发送。
5.3 调试时生成完整崩溃报告
若在 Xcode 中调试时发生崩溃,调试器会先接管,系统不会立即写盘。需要“完整崩溃报告”时:Debug → Detach(或 LLDB 中执行 detach),让进程继续运行直至退出,系统再生成报告;再按 5.2 方式在设备或 Mac 上找到该报告 [8]。
六、符号化操作 SOP
6.1 前置检查:UUID 一致
符号化前必须确认:崩溃报告里该二进制的 UUID 与 dSYM 的 UUID 一致。
- 从报告中找 Binary Images 里该镜像的 UUID(.ips 的
usedImages[].uuid;.crash 常在小括号内,小写无连字符)。 - 在终端执行 [2][3]:
dwarfdump --uuid <PathToDSYM>/Contents/Resources/DWARF/<BinaryName>
dwarfdump --uuid <PathToBinary>
两者一致才可用该 dSYM 符号化该二进制。
6.2 用 Xcode 符号化(推荐)
- 扩展名:确保报告为 .crash(.ips 若 Xcode 支持可直接拖,否则可先导出为 .crash 或保留 .ips 用命令行)。
- 打开 Devices and Simulators → 选中设备 → View Device Logs。
- 将崩溃报告文件拖入左侧日志列表。
- 若本机 Spotlight 可搜到对应 UUID 的 dSYM(例如在 ~/Library/Developer/Xcode/Archives 或项目 DerivedData),Xcode 会自动符号化;符号化后栈中会显示函数名与行号 [2]。
若未符号化或仅部分符号化:多为缺少匹配 dSYM 或系统框架符号缺失(需连接过对应系统版本的设备,让 Xcode 拉取系统符号)[2]。
6.3 用 symbolicatecrash 命令行
位置(随 Xcode 安装)[2][3]:
/Applications/Xcode.app/Contents/SharedFrameworks/DVTFoundation.framework/Versions/A/Resources/symbolicatecrash
环境变量(必须)[2][3]:
export DEVELOPER_DIR=/Applications/Xcode.app/Contents/Developer
用法示例 [2][3]:
symbolicatecrash /path/to/crash.crash /path/to/App.dSYM > symbolicated.txt
# 或指定 dSYM 目录
symbolicatecrash -d /path/to/dSYMs -o symbolicated.txt /path/to/crash.crash
- 支持一次传入多个 dSYM 或目录,工具会按报告中的 UUID 自动匹配。
- 输入必须是系统生成的完整崩溃报告(含 Binary Images),否则无法解析。
6.4 用 atos 单地址符号化
适用于:只有若干地址、或在 LLDB/脚本中对单帧反解。
公式 [2][3][7]:报告中某帧的运行时地址 = 该镜像在报告中的 base(load address) + 该帧的 imageOffset(.ips 中)或从 “base+offset” 形式中读出。
命令形式 [2][3]:
atos -arch <arch> -o <PathToDSYM>/Contents/Resources/DWARF/<BinaryName> -l <LoadAddress> <Address1> [Address2 ...]
示例(Binary 名为 TouchCanvas,arm64,base 0x1022c0000)[2]:
atos -arch arm64 -o TouchCanvas.app.dSYM/Contents/Resources/DWARF/TouchCanvas -l 0x1022c0000 0x00000001022df754
# 输出示例:ViewController.touchesEstimatedPropertiesUpdated(_:) (in TouchCanvas) + 304
- -o 必须是 dSYM 包内的 DWARF 文件路径,不能只写 .dSYM 包路径 [2]。
- -l 必须是该次运行中该镜像的 load address,在 Binary Images 中查。
6.5 用 Spotlight 查找本机 dSYM(按 UUID)
若已知 Binary 在报告中的 Build UUID(如 9cc89c5e55163f4ab40c5821e99f05c6),可转为标准格式(大写、8-4-4-4-12)再查 [2]:
mdfind "com_apple_xcode_dsym_uuids == 9CC89C5E-5516-3F4A-B40C-5821E99F05C6"
若返回路径,说明本机有该 dSYM,可再 dwarfdump --uuid 核对后用于 Xcode 或 symbolicatecrash。
6.6 符号化 SOP 速查
| 步骤 | 操作 |
|---|---|
| 1 | 拿到 .ips 或 .crash;若是 .txt,重命名为 .crash 以便 Xcode 识别 |
| 2 | 在报告底部 Binary Images 中确认主程序/Extension 的 UUID 与 arch |
| 3 | 用 mdfind "com_apple_xcode_dsym_uuids == <UUID>" 或 Archive 路径找到对应 dSYM,dwarfdump --uuid 核对 |
| 4 | 优先在 Xcode Device Logs 中拖入报告,由 Xcode 自动符号化 |
| 5 | 若需命令行:设置 DEVELOPER_DIR,用 symbolicatecrash 传入报告与 dSYM(或目录),输出到文件 |
| 6 | 若仅有个别地址:从 Binary Images 取 base,用 atos -arch -o -l 反解 |
七、异常类型与诊断要点
7.1 常见异常类型(Exception Type)
以下为 Apple 文档中常见类型与含义摘要 [10][11]:
| 异常类型 | 典型含义与排查方向 |
|---|---|
| EXC_BAD_ACCESS (SIGSEGV) | 非法或越界内存访问(野指针、已释放对象、栈溢出等)[10] |
| EXC_BAD_ACCESS (SIGBUS) | 错位访问、指针认证失败等 [10] |
| EXC_BREAKPOINT (SIGTRAP) | 陷阱指令触发;Swift 中常见于强制解包 nil、断言失败、fatalError 等 [10][11] |
| EXC_CRASH (SIGABRT) | 进程调用 abort() 或断言失败;常见于 NSException 未捕获、Objective-C 异常、断言 [10] |
| EXC_CRASH (SIGKILL) | 被系统终止:如 Watchdog、内存压力、用户强退等 [10] |
| EXC_CRASH (SIGTERM) | 软件终止信号 [10] |
| EXC_GUARD | 违反受保护资源(如文件描述符 guard)[10] |
| EXC_RESOURCE | 超过资源限制(CPU 时间、内存等)[10] |
| EXC_ARITHMETIC | 算术异常(如除零、浮点错误)[10] |
7.2 诊断时的使用方式
- 先看 Exception Type / signal 判断大类:内存问题、断言/abort、系统杀进程等。
- 结合 Exception Message / Termination Reason、Last Exception Backtrace(若有)缩小范围。
- Crashed Thread 的 Frame 0 与自家 App 的栈帧是首要关注点;系统库帧可帮助理解调用链(例如是否在 present popover、主线程卡顿等)[9]。
八、崩溃分析流程与解读
8.1 分析顺序建议(基于 Apple 文档 [9])
- 确认报告已充分符号化:至少自家 App 的栈帧要有函数名与行号;否则先按第六章完成符号化。
- 从用户视角找入口:根据栈中与业务相关的帧,推断用户当时在使用什么功能(例如某个 VC、某个 present)。
- 看 Header:设备型号、系统版本、App 版本、启动时间与崩溃时间(运行时长)、是否 TestFlight、主 App 还是 Extension 等,用于复现环境与分组。
- 看异常信息:Exception Type、Exception Codes、Termination Reason,判断是内存、断言、Watchdog 等哪一类。
- 看崩溃线程 backtrace:从 Frame 0 往上看,先关注自家代码;再结合 Last Exception Backtrace(若有)看“谁抛出了异常”。
- 看其它线程:是否有大量相似等待、是否涉及不该在非主线程调用的 API(如 UI)等 [9]。
- 复杂内存/寄存器问题:可结合 threadState 与 atos 对 PC/LR 等地址符号化,或参考 [Investigating memory access crashes] 等专项文档。
8.2 分组与复现
- 多份报告可按 相同 Exception Type + 相同栈顶帧 或 相同 Termination Reason 分组,便于判断是否为同一根因、是否可稳定复现 [9]。
- 用 Header 中的 CrashReporter Key / Beta Identifier 区分不同用户/设备,评估影响面。
8.3 系统符号与 Binary Images
- 若系统库帧未符号化,需在与报告系统版本一致的设备上连接 Xcode,让 Xcode 拉取该系统版本的符号;或在本机已有对应版本符号时,Xcode 才能反解系统帧 [2]。
- Binary Images 可用来确认:主程序与各 Framework/Extension 的 UUID、是否缺少预期加载的库(如动态加载的 framework)[9]。
九、关键概念图示与流程
9.1 崩溃报告生成与符号化数据流
flowchart LR
subgraph 设备
A[App 崩溃]
B[系统收集状态]
C[.ips / .crash]
end
subgraph 开发机
D[dSYM]
E[Xcode / symbolicatecrash / atos]
F[符号化报告]
end
A --> B --> C
C --> E
D --> E
E --> F
9.2 符号化匹配关系
flowchart TB
subgraph 崩溃报告
U1[Binary Images: UUID, base, name]
F1[Frames: imageIndex, imageOffset]
end
subgraph 本地
DSYM[dSYM: UUID, DWARF]
end
U1 -->|UUID 一致| DSYM
F1 -->|base + imageOffset = 运行时地址| atos
DSYM --> atos[atos / symbolicatecrash]
atos --> out[函数名 + 行号]
9.3 从获取到分析的流程
flowchart TD
A[获取 .ips / .crash] --> B{是否已符号化?}
B -->|否| C[按 UUID 找 dSYM]
C --> D[Xcode 拖入 或 symbolicatecrash/atos]
D --> E[得到符号化报告]
B -->|是| E
E --> F[看 Exception Type]
F --> G[看 Crashed Thread 栈顶与自家帧]
G --> H[结合 Last Exception / Termination]
H --> I[定位代码与复现路径]
十、伪代码与算法说明
10.1 判断报告是否已符号化
根据 Apple 文档 [2]:若 backtrace 中每一帧都包含可读函数名(而非“基址+偏移”或纯地址),则视为已完全符号化;若仅部分帧有函数名,为部分符号化;若全是地址或“基址+偏移”,为未符号化。
对于报告中的每个线程 thread:
对于 thread 的每个帧 frame:
若 frame 仅包含 "0x... + 数字" 或 "基址 + 偏移" 且无函数名:
返回 "未符号化"
若 存在任一 frame 无函数名:
返回 "部分符号化"
否则:
返回 "已符号化"
10.2 atos 使用的地址关系
报告中某帧的运行时地址与 load address(base)、imageOffset 关系 [2][7]:
运行时地址 = base(Binary Images 中该镜像的 base) + imageOffset(该帧相对该镜像的偏移)
atos 内部会用“运行时地址 - base”得到相对偏移,在 dSYM 的 DWARF 中查找对应符号与行号。因此 -l 必须传入该次运行的 base(从同一份报告的 Binary Images 读取)。
10.3 UUID 匹配与 dSYM 查找
1. 从崩溃报告 Binary Images 中取出目标镜像的 uuid 字符串(可能为小写、无连字符)。
2. 转为标准格式:32 字符,8-4-4-4-12,大写,连字符分隔。
3. 使用 mdfind "com_apple_xcode_dsym_uuids == <UUID>" 得到候选 dSYM 路径。
4. 对候选路径执行 dwarfdump --uuid <dSYM内DWARF路径>,与报告中的 uuid(忽略大小写与连字符)比较。
5. 一致则该 dSYM 可用于该二进制;否则需从 Archive 或构建产物中取正确版本。
十一、应用场景与最佳实践
11.1 构建与归档
- Release/分发构建 统一使用 DWARF with dSYM File,并保留每次分发的 Archive(含 dSYM)[4]。
- 上传 App Store/TestFlight 时勾选上传符号,便于 Organizer 中自动符号化 [2][4]。
11.2 第三方崩溃统计与符号上传
若使用 Firebase Crashlytics、Bugly、Sentry 等,需按各平台文档在构建阶段上传 dSYM(或符号表),以便其服务端对上报的堆栈做符号化 [12]。例如 Firebase 要求在 Xcode Build Phases 中配置上传脚本与 dSYM 路径 [12]。
11.3 .ips 与脚本化处理
- .ips 为 JSON,便于用脚本解析:取
bug_type==309、threads、usedImages、exception等,批量提取 UUID、faultingThread、栈顶帧等 [6][7]。 - 若需对大量报告做“是否可符号化”检查,可解析
usedImages中的uuid,与本地或符号服务器中的 dSYM UUID 列表比对。
11.4 常见崩溃模式与专项文档
- Swift 运行时错误:强制解包 nil(
!)、失败的类型转换(as!)、数组越界等,常表现为 EXC_BREAKPOINT (SIGTRAP) 或 EXC_BAD_INSTRUCTION (SIGILL);可结合 Addressing crashes from Swift runtime errors 排查。 - 未捕获的 Objective-C 异常:常为 EXC_CRASH (SIGABRT),需查看 Last Exception Backtrace 与 Exception Message。
- 内存访问问题:EXC_BAD_ACCESS、SIGSEGV/SIGBUS,需结合 VM Region Info、寄存器与 Investigating memory access crashes 分析 [14]。
- Watchdog / 系统终止:启动超时、主线程卡死等,可参考 Addressing watchdog terminations。
- 更多模式与字段说明见官方 Identifying the cause of common crashes [13]。
11.5 官方文档与延伸阅读
| 资源 | 用途 |
|---|---|
| Adding identifiable symbol names to a crash report | 符号化步骤、Xcode/atos、UUID、mdfind [2] |
| Analyzing a crash report | 分析顺序、Header/Exception/Backtrace/寄存器 [9] |
| Interpreting the JSON format of a crash report | .ips 结构、metadata、report 各键 [6][7] |
| Understanding the exception types in a crash report | 异常类型与信号含义 [10] |
| Acquiring crash reports and diagnostic logs | 获取途径、设备导出、Organizer [8] |
| Building your app to include debugging information | dSYM 生成、上传与归档 [4] |
| Identifying the cause of common crashes | 常见崩溃模式与排查思路 |
| Investigating memory access crashes | 内存访问崩溃深入分析 |
参考文献
[1] Apple. Understanding and Analyzing Application Crash Reports (TN2151).
[2] Apple. Adding identifiable symbol names to a crash report. developer.apple.com/documentati…
[3] Apple. Symbolicating iPhone App Crash Reports (Stack Overflow / 社区实践).
[4] Apple. Building your app to include debugging information. developer.apple.com/documentati…
[5] 阿里云. 苹果官方文档:理解和分析ios应用崩溃日志. developer.aliyun.com/article/239…
[6] Apple. Interpreting the JSON format of a crash report. developer.apple.com/documentati…
[7] Apple. Interpreting the JSON format of a crash report — Binary images, Frames, Convert numeric values.
[8] Apple. Acquiring crash reports and diagnostic logs. developer.apple.com/documentati…
[9] Apple. Analyzing a crash report. developer.apple.com/documentati…
[10] Apple. Understanding the exception types in a crash report. developer.apple.com/documentati…
[11] RY's Blog. EXC_BREAKPOINT when forced unwrapping optional in Swift.
[12] Firebase. 在 Crashlytics 信息中心内获取易于理解的崩溃报告(Apple 平台) / Get deobfuscated crash reports.
[13] Apple. Identifying the cause of common crashes. developer.apple.com/documentati…
[14] Apple. Investigating memory access crashes. developer.apple.com/documentati…