众所周知,苹果iOS 9的推新速度已经打破了纪录,9.1刚刚于上周推出后,昨天,9.2 beta1已经出来了。
那么,到底iOS9都有哪些坑?网上能够搜索到的那些大的方面,本文不再罗列,想必每一个使用Xcode7编译的App都已经做过了相关的工作。本文只讲本团队开发过程中遇到的非常小但却非常隐蔽的“坑”“坑”“坑”!
1问题的发现
某天,本团队正在如常监控App的Crash数据,突然发现其中多了几个特殊的Crash类型。经过汇总分析,发现了重现Crash的软硬件环境,于是尝试重现了一下,将系统升级到9.1beta,果然,启动App后发生了Crash。
看来,问题出现在layer的bounds的x坐标是nan。这种错误是在float经过函数运算出现了不是数字的值,通常这种情况是因为除以0造成的,而layer的bounds不接受nan值,所以出现了问题。
那么nan是在哪里产生的呢,经过debug确定问题点:
通过打印发现此时self.contentSize.width是0,所以造成movepercent的值是nan,之后使用nan进行赋值所以出现Crash。
那么问题来了:
1.scrollViewDidScroll:方法不是只有滑动屏幕或者设置contentoffset才被调用吗?2.程序刚刚启动,为什么会调用到scrollViewDidScroll:方法,是谁调用的。
3.调用scrollViewDidScroll:方法的时候contensize为什么是0呢,此时contensize应该已经被赋值才对。
4.为什么9.1beta版有问题而之前的版本没有问题呢。
2问题的分析
带着这些疑问继续debug:
通过上图我们发现两个版本之间的区别是9.1beta系统在App初始化阶段就调用了scrollViewDidScroll方法,而此时scroll的contentsize还没有被初始化(contentsize的default值是0),所以导致了nan问题的发生。
新的疑问又来了,两个版本都执行了_setNavigationControllerContentInsetAdjustment:方法,为什么9.1beta执行了scrollViewDidScroll,而9.1之前的版本没有执行此方法呢。
我们进一步debug如下图
我们发现两个版本之间的区别只是inset值不同,那么苹果会不会以inset的值来决定是否发送scrollViewDidScroll消息呢。
继续debug如下图
通过debug,我们发现只要inset的值不是0系统就会执行scrollViewDidScroll方法。而49刚好是我们tabbar的高度,虽然看不到sdk内部的实现但是应该可以推断9.1beta版本对初始化顺序进行了修改,导致scrollViewDidScroll被过早的调用(此时contensize还未初始化)。
3问题的解决
1.首先要对contentsize为0的情况进行容错,防止nan的产生 。
2.其次由于我们无法修改scrollViewDidScroll的调用时机,所以应该尽早初始化contensize(比如在scrollview的init)。
一般说来,iOS系统的更新,大版本的更新变动都比较大,比如6到7,7到8,8到9,但是像这种小版本的变动,尤其是底层实现的细微变动,真的是坑死人啊!
这还不算,由于苹果更新了Store下载的软件分发方式——大的变动总会有风险的,频频发生某些App无法更新的问题。对于微信这种用户必须的App还好,今天下不了,总有一天能下载的。但是对于其它App,就没有这么幸运了,今天下不了,用户直接就不用了。变动总是痛苦的,不仅仅是苹果,还有依赖苹果的我们:)
其实除了这些问题,还有许多细节的不偶遇就不相识的问题,都隐藏在iOS各处。对于我们开发能够做的,只能是尽量的提前测试、发现、兼容、再测试、再发现、再兼容!软件工程师真的很苦逼,塞班挂了,得学iOS;iOS更新了,还得继续学;永无止境!
顺便打个广告:鉴于发现问题的重要性,尤其是已经上架的版本,监控软件质量状态极为重要,因为用户场景各不相同,有些环境是测试部门抓破头皮也想不到的。所以,需要某种工具来收集、分类、定位Crash或bug日志。为了保障App质量,我们接入使用了专业Crash监测工具:腾讯Bugly。
Bugly是腾讯内部产品质量监控平台的外发版本,其主要功能是App发布以后,对用户侧发生的Crash以及卡顿现象进行监控并上报,让开发同学可以第一时间了解到App的质量情况,及时机型修改。目前腾讯内部所有的产品,均在使用其进行线上产品的崩溃监控。