Skip to content

Latest commit

 

History

History
69 lines (51 loc) · 2.92 KB

220.md

File metadata and controls

69 lines (51 loc) · 2.92 KB
contributors
zntfdr

All our collection views (both UITableView and UICollectionView) are getting an overdue refresh this year.

We no longer need to use IGListKit and the likes, we no longer need to call .reloadData() or performBatchUpdates().

Introducing:

In short, what we must do now in our collection views is inject one of the two data sources above.

These new data source types will manage a snapshot of our data state:

  • You can think of a snapshot as the collection view current state (you can query them the number of sections and rows per section and more).
  • The snapshot has elements, which can be our models instances, or just as an identifier of a model, that helps us identify unequivocally a data element. These elements must conform to Hashable.

Three steps:

  1. create a snapshot (you can start from the current snapshot, or create a new one)
  2. configure it
  3. apply to our data source

All is awesome for data sources now, what about our collection views delegates? No api changes, for them. However, the data source exposes a way to go from an indexPath to a identifier:

func collectionView(
  _ collectionView: UICollectionView,
  didSelectItemAt indexPath: IndexPath
) { 
  if let identifier = dataSource.itemIdentifier(for: indexPath) { 
    // Do something
  }
}

Therefore we get all the advantages of our new datasource in the delegate as well 👍🏻 Note: this indexPath -> identifier/object is done in constant time.

We can call apply() in a background thread.

⚠️ We must always call apply() from the background queue or the main queue. No mix!

Here’s an example of how to inject a data source:

func configureDataSource() { 
  dataSource = UICollectionViewDiffableDataSource 
    <Section, MountainsController.Mountain>(collectionView: mountainsCollectionView) { 
      (collectionView: UICollectionView, indexPath: IndexPath, mountain: MountainsController. Mountain) -> UICollectionViewCell? in 
    guard let mountainCell = collectionView.dequeueReusableCell(
      withReuseIdentifier: LabelCell.reuseIdentifier, for: indexPath) as? LabelCell else {
        fatalError("Cannot create new cell")
    } 
    mountainCell.label.text = mountain.name
    return mountainCell
  }
}

Note how we also pass the method to set and return a new cell when injecting it, most importantly, note how that method also passes our associated element at that index. We no longer need to do lookups etc.

Lastly, both the new data source types are generic (no objc), therefore we will need two (hashable) types, one for sections (an enum will suffice) and one for the elements (duh).