29. 稳定性治理
稳定性治理的目标是“可追溯、可定位、可恢复”。核心要素:崩溃采集、日志埋点、异常防护、灰度回滚。
一、崩溃类型与常见来源
- 访问越界(数组下标错误)
- 强解包失败
- UI 在子线程更新
- 循环引用导致内存异常
- 解析异常或空数据导致崩溃
二、崩溃捕获基础
1. Uncaught Exception
func handleException(_ exception: NSException) {
print("Exception: \(exception.name) \(exception.reason ?? "")")
}
NSSetUncaughtExceptionHandler { exception in
handleException(exception)
}
2. Signal 捕获
import Foundation
func handleSignal(_ signal: Int32) {
print("Signal: \(signal)")
}
signal(SIGABRT) { _ in handleSignal(SIGABRT) }
signal(SIGSEGV) { _ in handleSignal(SIGSEGV) }
signal(SIGBUS) { _ in handleSignal(SIGBUS) }
说明:以上只用于收集信息,真正的线上需要结合崩溃上报服务与符号化。
三、符号化流程
- 构建时保存 dSYM
- 崩溃日志使用 dSYM 符号化
- 线上崩溃必须确保 build 与 dSYM 对应
四、日志与埋点
1. 基础日志封装
enum LogLevel: String { case info, warn, error }
struct Logger {
static func log(_ level: LogLevel, _ message: String) {
print("[\(level.rawValue)] \(message)")
}
}
2. 关键流程打点
struct Trace {
static func event(_ name: String, params: [String: String]) {
print("event=\(name) params=\(params)")
}
}
五、常见防护策略
1. 数组越界保护
extension Array {
subscript(safe index: Int) -> Element? {
return indices.contains(index) ? self[index] : nil
}
}
2. 主线程检查
func assertMainThread() {
assert(Thread.isMainThread)
}
3. Optional 兜底
let title = response.title ?? ""
六、崩溃回溯与定位
- 崩溃点附近的用户操作
- 设备型号与系统版本
- 网络状态与请求链路
将这些维度打进日志,可以大幅缩短排查时间。
七、灰度与回滚
- 新功能先小流量灰度
- 线上异常迅速关闭开关
- 保留回滚版本,避免全量崩溃
稳定性是工程能力,不是单次修复。持续监控与可回滚策略是关键。