DiffableDataSource CollectionView returning no items in section

950 views Asked by At

Here is my class:

class MediaViewController: UIViewController{
    var collectionView: UICollectionView! = nil

    
    private lazy var dataSource = makeDataSource()

    fileprivate typealias DataSource = UICollectionViewDiffableDataSource<SectionLayoutKind, testRecord>

    fileprivate typealias DataSourceSnapshot = NSDiffableDataSourceSnapshot<SectionLayoutKind, testRecord>
   override func viewDidLoad() {
        super.viewDidLoad()
        setRecordItems()
        configureHierarchy()
        configureDataSource()
        applySnapshot()

    }
    
    func setRecordItems(){
        for i in 0...3{
            let record = testRecord(daysBack: i/2, progression: i/10)
            records.append(record)
        }
    }
extension MediaViewController {

    func configureHierarchy() {
        collectionView = UICollectionView(frame: view.bounds, collectionViewLayout: createLayout())
        collectionView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
        collectionView.backgroundColor = .systemBackground
        view.addSubview(collectionView)
        collectionView.delegate = self
    }
}
extension MediaViewController {

    fileprivate enum SectionLayoutKind: Int, CaseIterable{
        case records
        case timeline
    }
    fileprivate func makeDataSource() -> DataSource {
        let dataSource = DataSource(
            collectionView: collectionView,
            cellProvider: { (collectionView, indexPath, testRecord) ->
              UICollectionViewCell? in
              // 2
                switch indexPath.section {
                case 0:
                    let cell = collectionView.dequeueReusableCell(withReuseIdentifier: RecordCollectionViewCell.identifier, for: indexPath) as? RecordCollectionViewCell
                    cell?.configure(with: testRecord)
                    return cell
                case 1:
                    let cell = collectionView.dequeueReusableCell(withReuseIdentifier: TimelineDayCell.identifier, for: indexPath) as? TimelineDayCell
                    cell?.configure(with: testRecord)
                    return cell
                default:
                    return UICollectionViewCell()
                }
          })
          return dataSource
    }
    func configureDataSource() {
        collectionView.register(RecordCollectionViewCell.nib, forCellWithReuseIdentifier: RecordCollectionViewCell.identifier)
        collectionView.register(TimelineDayCell.nib, forCellWithReuseIdentifier: TimelineDayCell.identifier)
    }
    func applySnapshot(animatingDifferences: Bool = true) {
      // 2
      var snapshot = DataSourceSnapshot()
        SectionLayoutKind.allCases.forEach {
            snapshot.appendSections([$0])
            let records_copy = records
            snapshot.appendItems(records_copy, toSection: $0)
        }
      dataSource.apply(snapshot, animatingDifferences: animatingDifferences)
    }
}

So the setup is that there are two sections, records and timeline. These are both run by the same data - the records array. Currently I am copying this array from the class when I apply the snapshot each time - Im not sure its bad to use the same array for both for some reason..

Then when setting up the data source, for the cellProvider I have a switch statement that checks the section. If its section 0 Ill use a Record Cell and if its section 1 I will use a timeline cell.

Right now no record cells are being produced. When I check collectionView.numberOfItems(inSection:0) its 0. collectionView.numberOfItems(inSection:1) is 4 (the amount of records)

Why isn't it 4 for both sections? How can I do this?

1

There are 1 answers

4
matt On BEST ANSWER
  var snapshot = DataSourceSnapshot()
  SectionLayoutKind.allCases.forEach {
      snapshot.appendSections([$0])
      let records_copy = records
      snapshot.appendItems(records_copy, toSection: $0)
  }

So, let's consider what happens in that code. There are two cases in SectionLayoutKind.allCases, so the forEach runs twice.

  1. The first time, we append one section and then append four records to it.

  2. The second time, we append another section that then append the same four records to it. This effectively removes the four records from the first section and puts them in the second section.

Im not sure its bad to use the same array for both for some reason

It's not exactly "bad" but it certainly isn't getting you where you want to go. Remember, all items — not all items of the same section, but all items — must be unique. Obviously if you use the same four records twice, that's not unique. Unique doesn't mean whether it's the same or a different object. Uniqueness is determined by the Hashable / Equatable implementation of your cell identifier type, which in this case is testRecord. Your copies are identical, in that sense, to the original set of objects, so they count as the same as far as the diffable data source is concerned.

(You have not shown the testRecord type so I can't make further observations. But please, please, never again write code where a type begins with a small letter.)