collectionView踩坑(received layout

作者: dj_rose | 来源:发表于2018-12-18 15:34 被阅读3次

    前两天项目里遇到一个不太常见的collectionView的crash(标题起这么长是为了方便遇到同样问题的朋友能够快速检索到)

    UICollectionView received layout attributes for a cell with an index path that does not exist: 
    <NSIndexPath: 0x80b1dc933cf8f0de> {length = 2, path = 0 - 4}
    

    简单翻译一下:UICollectionView接收到了下标不存在的cell的布局属性。

    结合项目具体crash的场景发现:collectionView reloadData时,数据源已经变了,但是cell的layout attributes还没有更新,也就是collectionViewLayout出了故障。

    stackoverflow上看到很多人遇到了这个问题,解决办法五花八门,我试了一圈在这个场景下基本没用。

    说的最多的是在各个地方调用这句让布局失效的代码:

    [self.collectionView.collectionViewLayout invalidateLayout];
    

    这句代码从理论上讲应该是可以起作用的,然而我试了没什么卵用,后来我冷静下来思考了一下,既然是要让现有布局无效,不如我直接重新alloc一个collectionViewLayout好了。。

    即每次刷新数据之前调一下这个方法

    - (void)refreshFlowLayout
    {
        UICollectionViewFlowLayout *flowLayout = [[UICollectionViewFlowLayout alloc]init];
        self.vipCollectionView.collectionViewLayout = flowLayout;
    }
    

    就解决了。。

    collectionViewLayout为什么会发生故障,这个暂时还没有头绪,stackoverflow上也没人提到过,下周过来再研究研究。

    周一过来,又回头看这个问题,恰巧同事lkk跟我说:“你是不是改了啥,某处在模拟器上一直崩溃”。

    慌的一批,明明我的真机是不崩的,但是模拟器崩溃也是不能忍的,我也懒得管是否在部分版本系统上会崩溃了,直接回滚代码,重新寻找新的解决方案。。

    重新翻看stackoverflow的文章,一条一条的看,终于看到一条让我有所启发的comment:

    面向stackoverflow开发.png

    这边的意思是说当数据源发生变化的时候,先改变了contentInset再reloadData的话,就会crash,反之先reloadData再改变contentInset则是安全的!
    原因是改变contentInset会触发collectionView的布局更新,如果数据源改变时先改变contentInset(即先更新布局,再reloadData),layout attributes的数据和新的数据源不对应,发生崩溃也就不奇怪了~

    仔细看了下崩溃的相关代码,发现确实有这个骚操作😅

    于是把改变contentInset的方法放在reloadData后面执行就好了:


    change collectionView contentInset

    小结:第一种解决方案是在没有找到问题真正的根源时的无奈之举(周五晚上没吃晚饭的情况下,fix到实在饿的撑不住了的临时方案)。第二种方案则是刨根问底,寻找到问题的本源,从而对症下药。项目开发中,还是要尽可能的采用第二种思路去解决问题,否则项目的健壮性会越来越差。

    附:
    stackoverflow相关问题的链接

    相关文章

      网友评论

        本文标题:collectionView踩坑(received layout

        本文链接:https://www.haomeiwen.com/subject/xeclkqtx.html