CombineDataSources provides custom Combine subscribers that act as table and collection view controllers and bind a stream of element collections to table or collection sections with cells.
⚠️⚠️⚠️ Note 🚨🚨🚨: The package is currently work in progress.
The repo contains a demo app in the Example sub-folder that demonstrates the different ways to use CombineDataSources in practice.
Bind a plain list of elements
var data = PassthroughSubject<[Person], Never>()
data
.bind(subscriber: tableView.rowsSubscriber(cellIdentifier: "Cell", cellType: PersonCell.self, cellConfig: { cell, indexPath, model in
cell.nameLabel.text = model.name
}))
.store(in: &subscriptions)
Respectively for a collection view:
data
.bind(subscriber: collectionView.itemsSubscriber(cellIdentifier: "Cell", cellType: PersonCollectionCell.self, cellConfig: { cell, indexPath, model in
cell.nameLabel.text = model.name
cell.imageURL = URL(string: "https://api.adorable.io/avatars/100/\(model.name)")!
}))
.store(in: &subscriptions)
Bind a list of Section models
var data = PassthroughSubject<[Section<Person>], Never>()
data
.bind(subscriber: tableView.sectionsSubscriber(cellIdentifier: "Cell", cellType: PersonCell.self, cellConfig: { cell, indexPath, model in
cell.nameLabel.text = model.name
}))
.store(in: &subscriptions)
Customize the table controller
var data = PassthroughSubject<[[Person]], Never>()
let controller = TableViewItemsController<[[Person]]>(cellIdentifier: "Cell", cellType: PersonCell.self) { cell, indexPath, person in
cell.nameLabel.text = person.name
}
controller.animated = false
// More custom controller configuration ...
data
.bind(subscriber: tableView.sectionsSubscriber(controller))
.store(in: &subscriptions)
List loaded in batches
A common pattern for list views is to load a very long list of elements in “batches” or “pages”. (The distinction being that pages imply ordered, equal-length batches.)
CombineDataSources includes a data source allowing you to easily implement the batched list pattern called BatchesDataSource and a table view controller TableViewBatchesController which wraps loading items in batches via the said data source and managing your UI.
In case you want to implement your own custom logic, you can use directly the data source type:
let input = BatchesInput(
reload: resetSubject.eraseToAnyPublisher(),
loadNext: loadNextSubject.eraseToAnyPublisher()
)
let dataSource = BatchesDataSource<String>(
items: ["Initial Element"],
input: input,
initialToken: nil,
loadItemsWithToken: { token in
return MockAPI.requestBatchCustomToken(token)
})
dataSource is controlled via the two inputs:
input.reload (to reload the very first batch) and
loadNext (to load each next batch)
The data source has four outputs:
output.$items is the current list of elements,
output.$isLoading whether it’s currently fetching a batch of elements,
output.$isCompleted whether the data source fetched all available elements, and
output.$error which is a stream of Error? elements where errors by the loading closure will bubble up.
In case you’d like to use the provided controller the code is fairly simple as well. You use the standard table view items controller and TableViewBatchesController like so:
let itemsController = TableViewItemsController<[[String]]>(cellIdentifier: "Cell", cellType: UITableViewCell.self, cellConfig: { cell, indexPath, text in
cell.textLabel!.text = "\(indexPath.row+1). \(text)"
})
let tableController = TableViewBatchesController<String>(
tableView: tableView,
itemsController: itemsController,
initialToken: nil,
loadItemsWithToken: { nextToken in
MockAPI.requestBatch(token: nextToken)
}
)
tableController will set the table view data source, fetch items, and display cells with the proper animations.
Todo
much better README, pls
use a @Published for the time being instead of withLatestFrom
make the batches data source prepend or append the new batch (e.g. new items come from the top or at the bottom)
cover every API with tests
make the default batches view controller neater
add AppKit version of the data sources
support Cocoapods
Installation
Swift Package Manager
Add the following dependency to your Package.swift file:
CombineDataSources provides custom Combine subscribers that act as table and collection view controllers and bind a stream of element collections to table or collection sections with cells.
⚠️⚠️⚠️ Note 🚨🚨🚨: The package is currently work in progress.
Table of Contents
1.1 Bind a plain list of elements
1.2 Bind a list of Section models
1.2 Customize the list controller
1.3 List loaded in batches
2.1 Swift Package Manager
2.2 Cocoapods
License
Credits
Usage
Demo App 📱
The repo contains a demo app in the Example sub-folder that demonstrates the different ways to use CombineDataSources in practice.
Bind a plain list of elements
Respectively for a collection view:
Bind a list of Section models
Customize the table controller
List loaded in batches
A common pattern for list views is to load a very long list of elements in “batches” or “pages”. (The distinction being that pages imply ordered, equal-length batches.)
CombineDataSources includes a data source allowing you to easily implement the batched list pattern called
BatchesDataSource
and a table view controllerTableViewBatchesController
which wraps loading items in batches via the said data source and managing your UI.In case you want to implement your own custom logic, you can use directly the data source type:
dataSource
is controlled via the two inputs:input.reload
(to reload the very first batch) andloadNext
(to load each next batch)The data source has four outputs:
output.$items
is the current list of elements,output.$isLoading
whether it’s currently fetching a batch of elements,output.$isCompleted
whether the data source fetched all available elements, andoutput.$error
which is a stream ofError?
elements where errors by the loading closure will bubble up.In case you’d like to use the provided controller the code is fairly simple as well. You use the standard table view items controller and
TableViewBatchesController
like so:tableController
will set the table view data source, fetch items, and display cells with the proper animations.Todo
Installation
Swift Package Manager
Add the following dependency to your Package.swift file:
Cocoapods
Add the following dependency to your Podfile:
License
CombineOpenSource is available under the MIT license. See the LICENSE file for more info.
Combine Open Source
CombineOpenSource Slack channel: https://combineopensource.slack.com.
Sign up here
Credits
Created by Marin Todorov for CombineOpenSource.
📚 You can support me by checking out our Combine book: combinebook.com.
Inspired by RxDataSources and RxRealmDataSources.