Skip to content

RxCollectionViewSectionedAnimatedDataSource crash if estimatedItemSize was set in iOS 14.0&14.0.1 #416

@izhoubin

Description

@izhoubin

I have a problem here,and need your help.

  • UseRxCollectionViewSectionedAnimatedDataSource
  • The property estimatedItemSizewas set.
  • Use NSLayoutConstraint in UICollectionViewCell
  • iOS 14.0 or iOS 14.0.1(as i known)
  • Reload

It will always crash If the conditions above are met, in file 'RxCollectionViewSectionedAnimatedDataSource' at collectionView.performBatchUpdates(updateBlock, completion: nil) in both simulators and phones.

image

Xcode :Version 13.4 (13F17a)
System: macOS 12.3.1 (21E258)

You can reproduce by the following code and click Reload:

import UIKit
import RxDataSources
import RxCocoa
import RxSwift
class ViewController: UIViewController {
    var collectionView:UICollectionView!
    var dataSouce:RxCollectionViewSectionedAnimatedDataSource<AnimatableSectionModel<Int,String>>!
    let items:BehaviorRelay<[String]> = BehaviorRelay(value:["1","2","3","4","5","6"])
    let disposeBag:DisposeBag = DisposeBag()
    override func viewDidLoad() {
        super.viewDidLoad()
        setupCollectionView()
        setupReload()
        setupRx()
    }
    func setupReload(){
        let reloadButton = UIButton()
        reloadButton.setTitle("Click here to reload", for: UIControl.State.normal)
        reloadButton.setTitleColor(UIColor.black, for: UIControl.State.normal)
        view.addSubview(reloadButton)
        reloadButton.frame.size = CGSize(width: 200, height: 50)
        reloadButton.center = view.center
        reloadButton.addTarget(self, action: #selector(reload), for: UIControl.Event.touchUpInside)
    }
    @objc func reload(){
        items.accept(items.value.shuffled())
    }
    
    func setupCollectionView(){
        let layout = UICollectionViewFlowLayout()
        //crash when reload if 'estimatedItemSize' is set in iOS 14.0 & 14.0.1
        layout.estimatedItemSize = CGSize(width: 80, height: 50)
        layout.minimumLineSpacing = 10
        layout.minimumInteritemSpacing = 10
        collectionView = UICollectionView(frame: UIScreen.main.bounds, collectionViewLayout: layout)
        collectionView.backgroundColor = UIColor.white
        view.addSubview(collectionView)
        
        collectionView.register(CollectionViewCell.self, forCellWithReuseIdentifier: "CollectionViewCell")
    }
    
    func setupRx(){
        dataSouce = RxCollectionViewSectionedAnimatedDataSource<AnimatableSectionModel<Int,String>>(configureCell: {(dt, collectionView, indexPath, model) -> UICollectionViewCell in
            let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "CollectionViewCell", for: indexPath) as! CollectionViewCell
            cell.backgroundColor = UIColor.blue
            cell.label.text = model
            return cell
        })
        items
            .map{[AnimatableSectionModel(model: 0, items: $0)]}
            .bind(to:collectionView.rx.items(dataSource: dataSouce))
            .disposed(by:disposeBag)
        
    }
}
class CollectionViewCell: UICollectionViewCell {
    let label = UILabel()
    override init(frame: CGRect) {
        super.init(frame: frame)
        contentView.addSubview(label)
        label.textAlignment = .center
        label.font = UIFont.systemFont(ofSize: 30)
        label.backgroundColor = UIColor.yellow
        contentView.backgroundColor = UIColor.purple
        label.translatesAutoresizingMaskIntoConstraints = false
        NSLayoutConstraint(item: label, attribute: .left, relatedBy: .equal, toItem: contentView, attribute: .left, multiplier: 1, constant: 10).isActive = true
        NSLayoutConstraint(item: label, attribute: .right, relatedBy: .equal, toItem: contentView, attribute: .right, multiplier: 1, constant: -10).isActive = true
        NSLayoutConstraint(item: label, attribute: .top, relatedBy: .equal, toItem: contentView, attribute: .top, multiplier: 1, constant: 10).isActive = true
        NSLayoutConstraint(item: label, attribute: .bottom, relatedBy: .equal, toItem: contentView, attribute: .bottom, multiplier: 1, constant: -10).isActive = true
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions