Activity 1
Filter with snapshots
Build All, In Progress, and Complete filters that generate snapshots from one lesson store while preserving item IDs.
Hint: The filter changes membership and order, not identity.
UIKit Development
Drive lists from stable identity using snapshots, cell registrations, and repeatable content configurations.
Before you begin
Learning stage
A diffable data source represents list state as ordered section and item identifiers. Applying a new snapshot lets UIKit calculate inserts, deletes, moves, and updates from stable identity. Identifiers must be Hashable and stable; mutable display values generally should not define identity.
Cell registration pairs a cell type with an item type and a configuration handler. Create registrations once, then dequeue configured cells inside the data-source provider. Content configurations make each pass derive appearance from the current item, which works naturally with reuse and state changes.
A snapshot is UI state, not the database itself. Build it from the current source of truth on the main actor. For an item whose identity is unchanged but visible content changed, reconfigure or reload that identifier. Avoid overlapping snapshot applications and make empty, loading, and error states explicit outside fabricated rows.
Learning stage
A list data source joins stable lesson IDs back to current models and applies a new snapshot after filtering.
enum Section { case main }
private var lessonsByID: [Lesson.ID: Lesson] = [:]
private var dataSource: UICollectionViewDiffableDataSource<Section, Lesson.ID>!
private func configureDataSource() {
let registration = UICollectionView.CellRegistration<UICollectionViewListCell, Lesson> {
cell, _, lesson in
var content = cell.defaultContentConfiguration()
content.text = lesson.title
content.secondaryText = lesson.subtitle
cell.contentConfiguration = content
cell.accessories = lesson.isComplete ? [.checkmark()] : [.disclosureIndicator()]
}
dataSource = .init(collectionView: collectionView) { [weak self] collectionView, indexPath, id in
guard let lesson = self?.lessonsByID[id] else { return nil }
return collectionView.dequeueConfiguredReusableCell(using: registration,
for: indexPath,
item: lesson)
}
}
@MainActor
func show(_ lessons: [Lesson], animated: Bool) {
lessonsByID = Dictionary(uniqueKeysWithValues: lessons.map { ($0.id, $0) })
var snapshot = NSDiffableDataSourceSnapshot<Section, Lesson.ID>()
snapshot.appendSections([.main])
snapshot.appendItems(lessons.map(.id))
dataSource.apply(snapshot, animatingDifferences: animated)
}Learning stage
Connect the UIKit concept to complete, maintainable application features.
Learning stage
Identify lifecycle, ownership, identity, layout, accessibility, and user-experience risks.
Learning stage
Build the behavior in a small Xcode project and inspect it across realistic states.
Activity 1
Build All, In Progress, and Complete filters that generate snapshots from one lesson store while preserving item IDs.
Hint: The filter changes membership and order, not identity.
Activity 2
Update one lesson's progress and reconfigure its identifier without deleting and reinserting it.
Hint: Update the model store before applying the snapshot change.
Learning stage
Answer each question before revealing the explanation.
QUESTION 1
To determine which logical items moved, appeared, disappeared, or changed
Positions vary; identity lets the framework compare two ordered states safely.
QUESTION 2
Outside the cell-provider closure, usually while configuring the data source.
Recreating it inside the provider prevents correct reuse and can cause an exception.
Learning stage
Explain the design in terms of lifecycle, identity, ownership, system behavior, and trade-offs.
Short answer: It derives safe animated list updates by comparing snapshots of stable section and item identity.
Instead of manually coordinating index-path insertions, deletions, and moves, I construct the desired ordered identity state. UIKit calculates the transition. The model store still owns content, IDs remain stable, and registrations configure reusable cells from current data.
Possible follow-ups
Learning stage
Diffable data sources replace fragile positional update bookkeeping with snapshots of stable identity, while registrations make cell configuration repeatable.