Swift3+iOS8 下 UITableView 的神奇 bug

近期在我厂的实际项目中发现,在iOS 8系统中,Tableview cell 的排版出现了错乱,特别是在执行reloadRows:方法后,cell不仅会出现一个动画,最后高度还会不对,详情看动图:
swift_ios8_tablview_bug

后来经过层层排查,基本可以确定是系统的一个bug,在Swift3 + iOS 8的情况下才会出现。

排除可能的错误

高度计算有误?

出现这个问题后,从表面上看起来,似乎是高度计算有问题,但转念一想,我们用了高度缓存机制,高度只需要计算一次,只要第一次计算正确,后面再刷新不应该会出错呀。为了验证是不是高度有问题,采取了一个很简单的办法,直接将高度定死,设了一个固定值,发现没有这个动画和排版错误。因此初步得出结论是高度计算出现了问题。

于是接下来就是找到高度计算的问题。从bug表现来看,主要是cell的高度一开始基本是正常的(其实一开始也并不完全正常),主要是执行了reloadRows:方法后出问题,因此首先猜测是不是高度缓存出错了,缓存的key出问题了,还是中途哪里删除了缓存,然后再计算的时候就出错了。

然后通过打断点,一个个cell记录下key和高度,再和reloadRows:方法执行后的高度做对比,反复几次验证发现高度都没有问题,但它展示出来的实际高度就是不对,那就不是高度的问题,只能再找其它的原因。

隐性动画?

因为之前遇到过CALayer带来的隐性动画,导致cell出现奇怪的动画,因此接下来就猜测是不是这个原因。于是把cell中用到的Layer全部注释掉,但没有任何效果,依然有这个效果,而且从之前遇到的问题来看,隐性动画只会出现一个动画现象,不会出现高度不会的问题,那这个原因又可以排除了。

cell或者tableView设置有问题?

接下来就只能猜测是不是cell或者taleView哪里设置问题,立马验证。把tableView的自定义的设置全部注释,把自定义的cell换成系统的UITableViewCell,就这样已经把所有自定义的设置都删除后,问题依然存在。此时我内心真的是一万匹草泥马奔腾而过。这样看起来就不是我的代码写的有问题了。但我又不敢相信苹果会出现这么低级的bug,但我现在真的已经把所有可能的因素都排除了。联系其这个问题第一次出现是在升级到Swift3之后,接下来就只能猜测是不是跟Swift有关了。

Swift3的原因?

有了这个猜测,接下来就是用OC重写了一遍代码,然后运行,奇迹发生了,问题消失了,不管执行多少次reloadRows:cell都没有多余的动画,高度也完全正确,至此已经可以证明的确是Swift3的问题。具体的代码在我的github上:Swift3+iOS8-TableView ,大家可以自己在iOS 8的模拟器上试试。

如何解决?

那最重要的问题来了,这个bug该怎么解决,难道要我用OC重写一遍,这我是万分拒绝的。就在我快要放弃解决这个问题时,脑海里闪过tableView的一个属性estimatedRowHeight,这个属性是从iOS 7开始出现的,默认值0,根据文档,设置这个值能提高tableView在加载时计算高度的性能。既然能提高性能,那试试设置这个值,最后发现果然解决了问题。

实际上这个页面,之前在我们最低版本支持iOS 7时,在iOS 7上也出现过排版问题,但当时因为问题不是很严重,加上iOS 7的用户已经非常少,也快放弃了,就没有管。我都有点怀疑,是不是苹果故意留点bug,让开发者升级最低支持的版本。

我目前依然没有找到这个bug是如何产生的,如果有人知道,欢迎告诉我,不胜感激。

坚持原创技术分享,您的支持将鼓励我继续创作!