RxSwift ViewModel Example
Example of a ViewModel with RxSwift
- Protocol:
protocol TaskListViewModelType {
// Input
var addButtonDidTap: PublishSubject<Void> { get }
var itemDidSelect: PublishSubject<NSIndexPath> { get }
var itemDeleted: PublishSubject<NSIndexPath> { get }
// Output
var navigationBarTitle: Driver<String?> { get }
var sections: Driver<[TaskListSection]> { get }
var presentTaskEditViewModel: Driver<TaskEditViewModelType> { get }
}
ViewModel, conforms to protocol:
struct TaskListViewModel: TaskListViewModelType { // MARK: Input let addButtonDidTap = PublishSubject<Void>() let itemDidSelect = PublishSubject<NSIndexPath>() var itemDeleted = PublishSubject<NSIndexPath>()
// MARK: Output
let navigationBarTitle: Driver<String?>
let sections: Driver<[TaskListSection]>
let presentTaskEditViewModel: Driver<TaskEditViewModelType>
// MARK: Private
private let disposeBag = DisposeBag()
private var tasks: Variable<[Task]>
Initializer:
init() { let defaultTasks = [ Task(title: "Go to https://github.com/devxoul"), Task(title: "Star repositories I am intersted in"), Task(title: "Make a pull request"), ] let tasks = Variable<[Task]>(defaultTasks) self.tasks = tasks self.navigationBarTitle = .just("Tasks") self.sections = tasks.asObservable() .map { tasks in let cellModels = tasks.map(TaskCellModel.init) as [TaskCellModelType] let section = TaskListSection(model: Void(), items: cellModels) return [section] } .asDriver(onErrorJustReturn: )
self.itemDeleted
.subscribeNext { indexPath in
let task = tasks.value[indexPath.row]
Task.didDelete.onNext(task)
}
.addDisposableTo(self.disposeBag)
Continuation of Initializer - ViewController Navigation
// View Controller Navigations
let presentAddViewModel: Observable<TaskEditViewModelType> = self.addButtonDidTap
.map { TaskEditViewModel(mode: .New) }
let presentEditViewModel: Observable<TaskEditViewModelType> = self.itemDidSelect
.map { indexPath in
let task = tasks.value[indexPath.row]
return TaskEditViewModel(mode: .Edit(task))
}
self.presentTaskEditViewModel = Observable.of(presentAddViewModel,
presentEditViewModel).merge()
.asDriver(onErrorDriveWith: .empty())
- Continuation of Initializer - Model Service
// Model Service
Task.didCreate
.subscribeNext { task in
self.tasks.value.insert(task, atIndex: 0)
}
.addDisposableTo(self.disposeBag)
Task.didUpdate
.subscribeNext { task in
if let index = self.tasks.value.indexOf(task) {
self.tasks.value[index] = task
}
}
.addDisposableTo(self.disposeBag)
Task.didDelete
.subscribeNext { task in
if let index = self.tasks.value.indexOf(task) {
self.tasks.value.removeAtIndex(index)
}
}
.addDisposableTo(self.disposeBag)
}
}