关于XCode12 + iOS14的UITableViewCell ContentView 显示层级bug的探究。

问题描述

前几天在适配Xcode12 + iOS14发现了这样一个bug,因为在cell上添加视图的时候手抖没有把Button添加到TableViewCell的contentView上,而是直接添加到TableViewCell上,导致Button的点击事件全都无法响应。

后来查看层级发现怎么contentView跑到了视图最上层??

image

探究过程

第一直觉是XCode12 + iOS14上苹果改了底层实现把ContentView放到了最上层,就出现了这的问题(其实并不是这样的,后面会讲原因)。

最近正好没那么忙打算具体探究一下问题的原因:

通过添加 -[UIView addSubview:]Symbolic BreakPoint的断点,来获取TableViewCell 添加 contentView的具体时机和调用堆栈。

image
image

ContentView 添加到Cell上的时机:

在iOS14以前:

contentView是在[UITableViewCell initWithStyle:resueIdentifier]的初始化时第一个添加到View上。所以在最底层。

image

在iOS14上:

contentView 使用的是懒加载的方式生成。 在 cell即将要显示,调用
-[UITableView _configureCellForDisplay:forIndexPath:]_block_invoke的时候需要调整ContentView的布局,懒加载生成ContentView 并加载到Cell上。 所以就有了ContentView在最上层的bug了。

image

再通过对比iOS13和iOS14的Cell的初始化方法[UITableViewCell initWithStyle:reuseIdentifier:]断点调试。

发现 iOS14上Cell的init方法多出了_UITableViewCellEnableLazyContentView的方法,可以完全不用懂汇编,通过方法名就可以知道在iOS14上ContentView使用的是懒加载生成的。
_UITableViewCellEnableLazyContentView是一个默认返回true的方法,返回值为true的话在Cell的初始化方法中默认不初始化ContentView。 而是在调用的时候才创建ContentView并添加到Cell上

image

Test一下:

这里写一个最简单的cell,只添加一个红色的按钮。
只是在addSubView(redButton)之前随便调用一下contentView的lazy方法,这里就设置个绿色的背景色。

image

这个时候绿色的contentView就又回到了redButton后面😅😅。。正常了。。


image

感兴趣的同学可以写个Demo感受一下。

感悟:

这个妥妥是苹果的bug。

可能是疫情的时候哪个阿三在家状态不好没有考虑完全写出了这样的逻辑。

在Xcode12.2和iOS14正式版本这个bug还没有修。。

可能是不打算修了。。

最近作为苹果开发者,幸福感急剧下降啊。。