深入理解代替单纯记忆
过往工作经历中基本没碰到过关于崩溃的防护内容,但发现面试中会有类似问题,于是做了一点调研工作。本文简单说以下相关技术点、现状和个人思考
本文主要聊一下如下几个问题:
- 都有哪些崩溃可以防护
- 国内大多数是咋样防护的
- 国外App也这样做吗
- 个人看法
什么是崩溃防护
崩溃防护并非舶来品,是地道的国产名词
大致意思是,针对不同类型崩溃的特点,对潜在的崩溃进行提前的干预
- 一方面尽可能避免崩溃的发生,即使避免不了也通过更温和的方式提醒用户,而非直接闪退
- 另一方面,还要记录并上报下本次潜在的崩溃的信息,以供后续修复
哪些崩溃可以防护
常见的崩溃情况如下:
- unrecognized selector crash
- KVO crash
- NSNotification crash
- NSTimer crash
- Container crash(数组越界,插nil等)
- NSString crash (字符串操作的crash)
- Bad Access crash (野指针)
- UI not on Main Thread Crash (非主线程刷UI)
国外App是怎么做的
我在stackoverflow和medium上搜索“iOS prevent crash”之类的关键词,一条有价值的内容都没搜到
如何防护
看了几篇文章后,发现对于上面的crash,基本的防护措施就两方面:
- 非内存问题,通过Method Swizzling进行提前干预,避免崩溃
- 内存问题(野指针),创建自定义Zombie对象,延迟真实对象的释放,来监控和规避野指针问题
个人看法
先说结论:不推荐做crash防护
上面提到的crash防护措施,本质上是通过技术手段去为开发者编码错误兜底,我们从付出的代价和受益上简单比较一下:
- 使用Method Swizzling技术或Zombie没有错,但防护方案中依赖了较多的不确定性因素,比如
- 选择创建Zombie对象的时机如何选择,到底在dealloc还是在底层free函数执行时?如果后续某个版本iOS SDK变化了怎么办?(实际上这种情况已经发生了,第一个参考文档中有提到)
- 一些系统类的内部使用了类簇或使用了消息转发等机制,这些技术会与防护方案有冲突
- 到了Swift,没有runtime了,防护方案可能大功能就不能用了
- 第一篇参考文档中有提到,因为方案中在系统调用之前增加了很多逻辑,性能降低明显。且有的防护措施实际应用并没有预想的多,但却因为iOS设备、系统版本较多的原因,维护工作量不小
简单来说,不论是像数组越界这种低级的编码错误,还是内存管理理解不到位导致的内存泄漏或野指针错误,都不应该丢给兜底方案,谁的错谁来承担,能力达不到就多学习
与其做价值不太大的crash防护,我认为更有价值的内容是:
- 通过研究iOS/OS X操作系统底层原理,深入了解崩溃、异常、信号的内容(美团的欧阳大哥曾写过一个系列,从汇编开始认识崩溃内容)
- 学习深入解读崩溃文件,了解其中的偏移量、镜像等概念(曾遇到一个国外公司的面试题:如何在只要崩溃文件但没有dSYM文件的情况下了解具体的崩溃信息)
- 研究crash SDK是如何监控和收集crash