【iOS】iOS崩溃总结
【iOS】iOS崩溃总结
一、前言
之前写了一篇博文《【Flutter】程序报错导致的灰屏总结》,浏览量、收藏率和点赞量还挺高,还被收录了,就想着总结一下iOS崩溃
,这个也是在iOS面试中经常被问到的。
在 iOS 开发过程中,导致 App 崩溃的原因多种多样,大致可以分为以下几大类,
还是很想说,代码规范很重要,代码格式化也能方便我们查找BUG!!!
二、内存相关问题
-
访问野指针(野地址)
- 访问已经被释放的对象(Use After Free)
- 常见崩溃提示:
EXC_BAD_ACCESS
、SIGSEGV
-
内存泄漏造成系统回收进程(OOM)
- 未释放的内存持续增长,导致系统强制杀掉进程
- 通常无法捕获崩溃日志,但系统会记录在
JetsamEvent
中
-
循环引用
block
中引用self
、delegate
没有用weak
,导致对象无法释放
三、多线程问题
-
👉🏻 线程安全问题
- 多线程读写同一数据结构,导致崩溃或数据错乱
-
👉🏻 死锁
- dispatch_sync 嵌套调用自己,或等待永远不会结束的任务
-
👉🏻 后台线程更新 UI
- UIKit 只能在主线程使用,在子线程操作 UI 会崩溃
四、数组、字典越界或非法数据
-
👉🏻 数组越界
NSArray *array = @[]; NSLog(@"%@", array[1]); // 崩溃
-
👉🏻 向不可变字典中插入 nil
[@{@"key": nil} mutableCopy]; // 崩溃
-
👉🏻 非法类型转换
[someObject stringByAppendingString:@"test"]
,但 someObject 实际是 NSNull
五、KVO/KVC 相关
-
👉🏻 KVO 崩溃
- 重复添加或移除观察者
- 在对象释放前未移除观察者
- 修改未定义 keyPath
-
👉🏻 KVC 崩溃
setValue:forKey:
时 key 错误- 对私有变量或不存在属性赋值
六、UI相关问题
-
👉🏻 约束冲突导致 UI 崩溃
- AutoLayout 添加了冲突的 constraint
-
👉🏻 Storyboard / XIB 使用错误
- IBOutlet 未连接或连接错误
- 控件在 XIB 中已删除,但代码中仍引用
-
👉🏻 未处理的手势或交互崩溃
- 比如使用
UIPanGestureRecognizer
时 target 指针已释放
- 比如使用
七、文件和路径操作问题
-
👉🏻 文件路径为空或错误
- 使用
NSString *path = nil; [NSData dataWithContentsOfFile:path];
- 使用
-
👉🏻 访问沙盒外非法路径
- iOS 不允许访问 App 沙盒外的文件路径
八、网络或 JSON 解析异常
-
👉🏻 JSON 结构变化或数据缺失
- 使用
NSJSONSerialization
时返回了 null - 使用 Model 框架(如 YYModel、MJExtension)时解析 nil 或错误类型字段
- 使用
九、未捕获的异常
- 👉🏻 未使用
try-catch
包裹潜在异常代码(如 NSException) - 👉🏻 使用断言(NSAssert)在 Release 模式中崩溃
十、符号错误 / 动态库加载失败
-
👉🏻 dlsym 找不到符号
- 使用动态库(如 C 语言、Go 编译为 static lib)时忘记导出符号或链接失败
-
👉🏻 调用系统私有 API
- 在审核或某些系统中崩溃
十一、其他系统行为
-
👉🏻 App 被系统强制终止
- 使用过多内存、后台违规行为等
- iOS 低电量或资源紧张时杀掉后台 App
-
👉🏻 权限未申请导致崩溃
- 相机、麦克风、定位等未正确配置权限描述
十二、总结&工具
👉🏻 总结
1. 内存相关问题
- 针对于内存相关的崩溃,要养成良好的开发习惯,
定期使用Instruments排查一下,还有就是内存泄露或者暴涨,可以在基类的销毁方法里面打印一下delloc
,如果页面销毁没有打印,及时检查一下相关的逻辑, - 还有一些导致内存暴涨的,比如加载大图,如果使用
imageNamed:
会缓存,可以使用imageWithContentsOfFile:
; - 还有可以复用的场景,比如自定义的试图View;
2. 多线程问题
- 关于线程不安全访问,可以用 dispatch_queue 同步访问共享资源,也可以用 @synchronized 或 NSLock 等锁机制,还可以封装线程安全类;
- 对于死锁,避免 dispatch_sync 嵌套调用当前 queue,使用主线程 dispatch_async 更新 UI
- 在子线程更新UI,可以使用
dispatch_async(dispatch_get_main_queue(), ^{ // UI操作 });
3. 集合类崩溃问题
这个就很好解决了,网上有封装好的安全插入或者存储的库,都是使用runtime
写的。
4. KVO / KVC 崩溃
- 可以封装 KVO,推荐使用
FBKVOController
,iOS 11 起建议使用NSKeyValueObservation
替代手动 add/remove; - (void)setValue:forUndefinedKey:
中打日志避免崩溃,对 model 层添加@property
完整定义,不让非法 key 存在;
5. UI 崩溃 & 防护
- 针对于Storyboard/XIB 连接错误,每次修改 IBOutlet 后编译验证,控件删除时一并移除 IBOutlet;
- AutoLayout 崩溃,设置约束时避免冲突(使用 >=、<= 等)
6. 文件/路径/JSON 解析
- 针对于nil或者非法值,可以使用
fileExistsAtPath
- 如果是JSON 解析字段缺失或类型不匹配,可以使用 isKindOfClass 判断类型,还可以封装 Model 层容错代码(如缺字段时默认值)
7. 权限问题
- 一个是添加plist权限字段
- 还有就是在使用前,做一下权限的判断;
8. 其他高风险点
- 可以使用断言
- 使用
@try @catch
,但是我不建议使用@try @catch
,这样会导致问题一直无法被暴露
👉🏻 工具
工具 | 功能 |
---|---|
Xcode Debugger | 崩溃堆栈分析、调试器跟踪 |
Crashlytics | 崩溃日志收集平台 |
Bugly / Sentry | 支持符号化和用户设备统计 |
Instruments | 内存泄漏、对象分配分析 |
Address Sanitizer | 运行时检测内存访问越界等问题 |
十三、关于作者(ZFJ_张福杰)
- 官网:https://zfjsafe.com
- 博客:https://zfj1128.blog.csdn.net
- Github:https://github.com/zfjsyqk
- Gitee:https://gitee.com/zfj1128
- 打赏:https://zfjsafe.com/paycode