一次有意思的iPhone X上的递归bug

起因

我们公司上线了一个新版本之后,没有对iPhone X有针对性的重新设计UI,照理只是做了简单的视觉适配,比如navigationBar和一些自定义的bottomBar,对于其他的UI并没有特别的操作。
于是,在一个清晨的时候,当我打开fabric的时候,发现我们的主页出现了崩溃,而且居然是递归崩溃,仔细查看之后发现只在iPhone X上出现。

具体如下两图:


bug位置以及设备
一次有意思的iPhone X上的递归bug_第1张图片
具体调用栈

梳理逻辑

我们仔细梳理了一下首页的UI逻辑:

1、首页利用scrollViewDidScroll:这个方法了监测首页的滑动,当滑动范围超过20pt的时候,通过滑动方向来控制隐藏和展示navigationBar
2、进入首页之后,或者切换首页Tab的时候回触发mj_headerbeginRefreshing方法,自定义之后的mj_header的默认高度为52pt。
3、navigationBar的默认高度为44pt;
4、根据问题只出现在iPhone X上,可以猜测是当navigationBar执行隐藏的时候,和其他设备的UI布局处理逻辑不同。

分析了一下崩溃日志:

1、scrollViewDidScroll:这个方法被触发后,会根据互动距离以及方向类设置navigationBar隐藏或者展示。
2、navigationBar隐藏或者展示又反过来不断触发了scrollViewDidScroll:这个方法。

复现成功

navigationBar隐藏情况下,切换Tab到一个新的页面,出现mj_header刷新的UI之后出现崩溃。

分析原因

既然是递归,那么就要先找到loop的入口,这样才好找出口。
1、分析崩溃日志之后,发现一个很有意思的地方,当navigationBar隐藏或者展示的时候,会触发scrollViewDidScroll:这个方法,navigationBar的高度是44pt。
2、而当我们在navigationBar隐藏情况下,切换Tab到一个新的页面的时候,触发mj_headerbeginRefreshing方法,继而触发scrollViewDidScroll:mj_header*的默认高度为52pt,滑动距离的阈值是20pt。

所以我们简单推断出,这个递归问题的出现很有可能和这几个数字有关系。

得出结论

最后判断出结论是和我们设置的滑动距离的阈值有关系。
逻辑是这样的:
1、当触发mj_headerbeginRefreshing方法得时候,scrollViewDidScroll:也会触发,产生的间隔是52pt,大于滑动的阈值20pt。于是会触发navigationBar的展示方法。
2、当navigationBar的展示方法触发之后,又会触发scrollViewDidScroll:,产生的间隔是44pt,也大于滑动的阈值20pt。但是这个时候根据我们的判断逻辑,会判断滑动方向是向上的,所以会触发当navigationBar的隐藏方法。
3、当navigationBar的隐藏方法触发之后,又会触发scrollViewDidScroll:,产生的间隔依然是44pt,依然也大于滑动的阈值20pt。这个时候会判断为滑动方向是向下的,于是会触发当navigationBar的展示方法。
4、于是周而复始,产生了递归。

解决方案

解决递归的方案只有一种思路,为loop寻找一个出口。
根据上面的复现规律得出一个结论,之所以产生了递归,是不断的触发scrollViewDidScroll:方法的时候,产生的间隔均大于阈值。
那么,当我们将阈值提高到比44pt大之后,每次navigationBar的展示和隐藏方法所触发产生的距离将会小于这个预设的阈值,于是就不会进入向上向下滑动方向的判断逻辑,继而也就不会执行展示和隐藏方法,这样就算给loop找到了一个相当于优雅的出口。

总结

在处理UI问题的时候,虽然适配机型过程中会出现各种各样的问题,当问题出现的时候,我们需要一定要抓住触发的原因,这样才能更好的思考如何去绕过这个原因,以来解决问题。

你可能感兴趣的:(一次有意思的iPhone X上的递归bug)