Data-driven, declarative, reactive, diffable collections (and lists!) for iOS. A thoughtful and flexible wrapper for UICollectionView done right.
This project is close to finished for an initial release. I started this a few years back, then got busy with other things. I am now returning to the project to get the initial release complete. In any case, what's here now is worth sharing.
This library is the culmination of everything I learned from building and maintaining IGListKit, ReactiveLists, and JSQDataSourcesKit. The 4th time's a charm! 🍀
Improvements over the libraries above include:
- All Swift and zero third-party dependencies
- Generic view models to represent and configure cells
- Mix multiple data types
- Automatic registration for cells and supplementary views
- Automatic diffing for items and sections
- Simply
UICollectionView
,UICollectionViewCompositionalLayout
, andUICollectionViewDiffableDataSource
at its core. - No
UITableView
. OnlyUICollectionView
, which now has a List Layout.
SwiftUI performance is still a significant issue, not to mention all the bugs and missing APIs. SwiftUI still does not provide a proper UICollectionView
replacement. (Yes, Grid
exists but it is nowhere close to a replacement for UICollectionView
and UICollectionViewLayout
.) While SwiftUI's List
is pretty good, both LazyVStack
and LazyHStack
suffer from severe performance issues when you have large amounts of data.
TODO
⚠️ Work-In-Progress⚠️
Tip
Check out the extensive example project included in this repo.
Here's an example of building a simple, static list from an array of data models.
class MyViewController: UICollectionViewController, CellEventCoordinator {
var driver: CollectionViewDriver!
override func viewDidLoad() {
super.viewDidLoad()
let models = [/* array of some data models */]
// create cell view models from the data models
let cellViewModels = models.map {
MyCellViewModel($0)
}
// create your sections, and add cells
let section = SectionViewModel(id: "my_section", cells: cellViewModels)
// create the collection with all the sections
let collectionViewModel = CollectionViewModel(sections: [section])
// create your collection view layout
let layout = UICollectionViewCompositionalLayout.list(
using: .init(appearance: .insetGrouped)
)
// initialize the driver will all of the above
self.driver = CollectionViewDriver(
view: self.collectionView,
layout: layout,
viewModel: collectionViewModel,
cellEventCoordinator: self
)
// the collection is updated and animated automatically
// later, you can update the model like so:
let updatedCollectionViewModel = CollectionViewModel(sections: [/* updated items and sections */])
self.driver.viewModel = updatedCollectionViewModel
}
// MARK: CellEventCoordinator
func didSelectCell(viewModel: any CellViewModel) {
// TODO: handle cell selection events
}
}
- iOS 15.0+
- Swift 5.9+
- Xcode 15.0+
- SwiftLint
dependencies: [
.package(url: "https://github.com/jessesquires/ReactiveCollectionsKit.git", from: "0.1.0")
]
Alternatively, you can add the package directly via Xcode.
You can read the documentation here. Generated with jazzy. Hosted by GitHub Pages.
- Implementing Modern Collection Views, Apple Dev Docs
- Updating Collection Views Using Diffable Data Sources, Apple Dev Docs
- Prefetching collection view data, Apple Dev Docs
- Building High-Performance Lists and Collection Views, Apple Dev Docs
- Make blazing fast lists and collection views, WWDC21
- Advances in diffable data sources, WWDC20
- Advances in UICollectionView, WWDC20
- Lists in UICollectionView, WWDC20
- Modern cell configuration, WWDC20
- Creating Lists with Collection View, Use Your Loaf
- Getting Started with
UICollectionViewCompositionalLayout
, Lickability - The Case for Lists in UICollectionView, PSPDFKit Blog
- CompositionalDiffablePlayground, Filip Němeček
Interested in making contributions to this project? Please review the guides below.
Also, consider sponsoring this project or buying my apps! ✌️
Created and maintained by Jesse Squires.
Released under the MIT License. See LICENSE
for details.
Copyright © 2019-present Jesse Squires.