We will start out in a single view app with a tableView. Open up the starter project for this chapter, and you will see that we have created a searchController and configured it using configureSearchController() to include the searchBar of the searchController as the tableHeaderView of tableView, as follows:
func configureSearchController() {
searchController.obscuresBackgroundDuringPresentation = false
searchBar.showsCancelButton = true
searchBar.text = "scotteg"
searchBar.placeholder = "Enter GitHub ID, e.g., "scotteg""
tableView.tableHeaderView = searchController.searchBar
definesPresentationContext = true
}
Also, we have already bound the data sequence of a viewModel to the tableView, as shown:
viewModel.data
.drive(tableView.rx.items(cellIdentifier: "Cell")) { _, repository, cell in
cell.textLabel?.text = repository.name
cell.detailTextLabel?.text = repository.url
}
.addDisposableTo(disposeBag)
This is the first time we are actually using a viewModel in this book. We have used the same rx.items(cellIdentifier), which we discussed while working with tableViews in the previous chapters. We have created a struct repository with repoName and repoURL string properties, as follows:
struct Repository {
let repoName: String
let repoURL: String
}
Also, we have defined a viewModel class with a searchText variable of string as shown:
class ViewModel {
let searchText = Variable("")
lazy var data: Driver<[Repository]> = {
return Observable.of([Repository]()).asDriver(onErrorJustReturn: [])
}()
}
The purpose of a viewModel is to abstract from the code that prepares the data for use by the viewController, such as binding to the UI. The data property just has a placeholder return so that this project will compile. We will replace it shortly. This data sequence is implemented as a Driver of array of repository—Driver<[Repository]>—and as we see in the viewController, it'll drive the tableView. Remember that Driver will not emit an error, and it will automatically deliver events on the main thread.