对iOS中崩溃防护的思考

276 阅读3分钟

深入理解代替单纯记忆

过往工作经历中基本没碰到过关于崩溃的防护内容,但发现面试中会有类似问题,于是做了一点调研工作。本文简单说以下相关技术点、现状和个人思考

本文主要聊一下如下几个问题:

  1. 都有哪些崩溃可以防护
  2. 国内大多数是咋样防护的
  3. 国外App也这样做吗
  4. 个人看法

什么是崩溃防护

崩溃防护并非舶来品,是地道的国产名词

大致意思是,针对不同类型崩溃的特点,对潜在的崩溃进行提前的干预

  • 一方面尽可能避免崩溃的发生,即使避免不了也通过更温和的方式提醒用户,而非直接闪退
  • 另一方面,还要记录并上报下本次潜在的崩溃的信息,以供后续修复

哪些崩溃可以防护

常见的崩溃情况如下:

  • 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

参考