Skip to content

Instantly share code, notes, and snippets.

/// Now composing our `MVVM`
/// just like a plug and play
/// `Model`
let provider = ContactProvider()
/// `ViewModel`
let viewModel = ContactViewModel(provider)
/// `View`
let viewController = ContactViewController(viewModel)
/// `ContactViewController` = `View`
class ContactViewController: UIViewController {
private let bag = DisposeBag()
let viewModel: Contactable
/// `dependency inversion`
init(_ viewModel: Contactable) {
self.viewModel = viewModel
super.init(nibName: nil, bundle: nil)
configure()
/// `ContactViewModel` = `ViewModel`
class ContactViewModel: Contactable {
let datasource: Driver<[TableDatasource.Section]>
/// `dependency inversion`
init(_ provider: ContactProviderType) {
self.datasource = provider
.contacts
.map { items -> [TableDatasource.Section] in
/// groupedByNationality = [Nationality: [Person]]` ///new feature in swift 4.x
/// `TableDatasource`
class TableDatasource: NSObject, UITableViewDataSource, RxTableViewDataSourceType, SectionedViewDataSourceType, UITableViewDelegate {
struct Section {
let title: String
let rows: [TableRow]
init(title: String, rows: [TableRow]) {
self.title = title
self.rows = rows
}
/// `Contactable` = `ViewModel` requirement
protocol Contactable {
var datasource: Driver<[TableDatasource.Section]> {get}
}
/// `ContactProvider` = `Model`
class ContactProvider: ContactProviderType {
let contacts: Observable<Set<Person>>
init() {
/// Only Leader and the richest
/// Disclaimer this data is just
/// for example purposes. I am not
/// responsible for any incorrect
/// information. I hereby declare
/// `ContactProviderType` = `Model` requirement
protocol ContactProviderType {
/// Set that contains `Person`
var contacts: Observable<Set<Person>> {get}
}
/// `Person`
struct Person: Hashable {
let firstName: String
let lastName: String
let age: Int
let nationality: Nationality
}
//MARK: Two-way Bindings
extension ControlProperty {
func twoWayBindTo(_ variable: Variable<E>) -> Disposable {
let bindUI = variable.asObservable().bind(to: self)
let bindVariable = subscribe(
onNext: {value in
variable.value = value
}, onCompleted: {
bindUI.dispose()
})
/// Usage of shadowed protocol styled type erasure
let rows: [TableRow] = [ProductCell(name: "Hello"), ItemCell(id: "123456")]
for row in rows {
if let cell = row as? ProductCell {
cell.configure(with: Product())
}
if let cell = row as? ItemCell {
cell.configure(with: Item())