您的位置:首页 > 移动开发 > IOS开发

【团队分享】iOS8.3给发图带来的坑,怎样迅速填平?

2015-05-30 17:12 393 查看


向华,手机QQ项目团队,高级移动开发工程师,座右铭:Be The Best!

--------------------------------------------------------------------------

4月9号,苹果开始向iOS用户推送最新系统版本iOS8.3的升级。手机QQ团队第一时间进行系统升级的兼容性验证,发现在图片选择器界面切换标清图和原图时必现闪退现象。同时,在微博、论坛和support平台等渠道均有收到大量用户反馈此问题。

于是,我们迅速在厂内的崩溃统计分析平台(
小编注:
即Bugly平台
)查找相应崩溃问题的堆栈信息进行分析。

初步分析发现崩溃问题定位在
UIView addSubview
的调用,并有明确的错误信息:

<span style="font-size:12px;">Terminating app due to uncaught exception 'UIApplicationInvalidInterfaceOrientation', reason: 'Supported
orientations has no common orientation with the application, and
[QQMarkActionSheetController_FixPos shouldAutorotate] is returning
YES'</span>


我们进行了真机联调测试,验证崩溃问题必现场景同崩溃分析平台记录的一致。

再分析崩溃信息的详情,可以明确崩溃问题是由于
QQMarkActionSheetController_FixPos
的方向和
application
的方向不一致导致的。

于是,按照如下方法修复此问题:

1. 查找源码定位
QQMarkActionSheetController_FixPos
继承自
UIAlertController


2. 重写
shouldAutorotate
方法,返回值设为NO

重新编译调式验证,崩溃问题果然解决。

但正所谓“福无双至,祸不单行”,我们继续深入一些隐蔽场景测试,又发现两个必现崩溃的场景:

· 编辑图片后选择取消

· 关闭Wi-Fi后发送短视频

分析对比后,发现这两个场景有一个共同的业务逻辑,即是弹出
UIAlertView
进行消息提示,且崩溃的位置和错误的信息和前面提到的崩溃问题很相似:

<span style="font-size:12px;">Supported orientations has no common orientation with the application, and [_UIAlertShimPresentingViewController shouldAutorotate] is returning YES</span>


也是由于
_UIAlertShimPresentingViewController
的方向和
application
的方向不一致导致应用崩溃。

注意,此时,我们就不能跟前面提到的崩溃问题采用同样的方法进行修复了!

因为,
_UIAlertShimPresentingViewController
是系统内部的类,我们没法重写其
shouldAutorotate
方法。

所以,我们开始怀疑是否在iOS8.3系统中,是不是所有调用
UIAlertView
的地方都会发生崩溃?

但在选择了几个调用
UIAlertView
的界面进行验证后,发现并没有崩溃发生。这种情况让我们很是困惑,在一番探索后,我们把焦点转移到项目中二次封装的
SimpleAlertView
上,尝试把出现崩溃场景的
UIAlertView
换成
SimpleAlertView
,联调测试验证后发现崩溃问题没有再出现。

于是,我们得到一个解决此类崩溃问题的方法:

将工程中所有调用
UIAlertView
执行UI提示的逻辑全部替换为调用
SimpleAlertView
执行,当然,还需根据不同的场景修改适配UI样式和交互表现。

但古人有曰,三思而后行。

我们在工程中搜索
UIAlertView
的调用,发现竟有500+的调用,分别分布在300+的文件中,如果替换的话,其潜在风险和工作量都要仔细考量,而且还需针对不同场景修改UI样式和交互表现,不可取!

所以,我们否决了此解决方法,继续分析问题并探索其他的解决方法。

在前面的验证过程中,我们发现并非所有出现
UIAlertView
的界面都发生了崩溃,而是只有三个场景出现此类问题,而且都和图片选择器有关,于是把焦点又转移到图片选择器相关的逻辑,并进行了一系列的检查和验证:

1. Review代码,确认图片选择器里面的
shouldAutorotate
方法返回值确实为NO

2. 测试在3G环境下拍摄短视频发送,弹出流量提示框,无崩溃发生

3. 从图片选择器界面发送短视频,弹出流量提示框时,发生崩溃

由此,我们断定问题在图片选择器的相关处理中。

于是又搜索了其他场景使用
UIAlertView
但没有崩溃的代码,对比发现二者的
supportedInterfaceOrientations
方法有一些差异:

· 图片选择器的视图控制器里面
supportedInterfaceOrientations
方法返回值为
UIInterfaceOrientationPortrait


(NSUInteger) supportedInterfaceOrientations
{    return UIInterfaceOrientationPortrait;
}


· 其他场景的
supportedInterfaceOrientations
方法返回值为
UIInterfaceOrientationMaskPortrait


(NSUInteger) supportedInterfaceOrientations
{    return UIInterfaceOrientationMaskPortrait;
}


此处必有蹊跷!

我们火速进行修复尝试:

将图片选择器界面的视图控制器的
supportedInterfaceOrientations
方法返回值改为
UIInterfaceOrientationMaskPortrait


编译联调验证,果然没有发生崩溃。

我们断定在iOS8.3系统出现的
UIAlertView
发生崩溃的根本原因可能在于此,于是又将
QQMarkActionSheetController_FixPos
中重写的
shouldAutorotate
方法删除,测试验证发现没有发生崩溃,继续验证其他曾发生崩溃的场景,崩溃问题没有发生。

终于,我们得出此崩溃问题的根因。

崩溃原因总结

如果在视图控制器中重写
supportedInterfaceOrientations
方法,并将返回值设为
UIInterfaceOrientationPortrait
的话,那么在此视图控制器或子视图中弹出
UIAlertView
时,就会发生崩溃。

查阅了开发文档了解
supportedInterfaceOrientations
方法的使用,发现其返回值实际是
UIInterfaceOrientationMask
类型,而项目中却返回了
UIInterfaceOrientation
类型,二者虽然长得很相似,但用处完全不一样:

·
UIInterfaceOrientationMask
类型用来表示
UIViewController
能支持的方向

·
UIInterfaceOrientation
类型用来表示
application
当前的方向

如果在iOS8.3系统上两者混用,系统新增的检查判断会发现此问题,并抛出异常,崩溃就这样产生了。

小编有话说

· 在开发过程中对于系统常量的引用及其含义要加强关注,尤其是遇到此类“兄弟”模样的常量时,避免因理解不清或笔误而造成问题。

· 在系统版本更新时,要及时关注系统API和常量定义的变化,对功能代码进行兼容性调整。

不总结哪来经验,不分享经验何用?

在此小编号召大家多总结,互分享,踊跃给我们投稿,把自己踩过并爬出来的坑树个指示牌警醒后人,让猿们的开发生活更加美好!

投稿方式:将文章和个人介绍邮件到 bugly@tencent.com,字数不限

本文系腾讯Bugly特邀文章,转载请注明作者和出处“腾讯Bugly(http://bugly.qq.com)”
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: