class ProfileView { var refreshButton: Button var fullNameLabel: Label var ageLabel: Label var viewmodel: ProfileViewModelProtocol init(viewModel: ProfileViewModelProtocol) { self.viewModel = ProfileViewModel } func viewDidLoad() { viewModel.fullName.bind(to: fullNameLabel) viewModel.age.bind(to: ageLabel) viewModel.loading.bind(to: activityIndicator.isShowing) viewModel.errors.subscribeNext { error in showAlert(error) } view.pullToRefresh.tap.bind(to: viewmodel.didTapRefresh) } func showAlert(error: Error) { //Do something } } class LoginView { var userNameTextfield var passwordTextfield var loginButton var loading var errors func viewDidLoad() { userNameTextfield.rx_textfield.bind(to: viewmodel.username) passwordTextfield.rx_textfield.bind(to: viewmodel.password) loginButton.rx_tap.bind(to: viewmodel.didTapLogin) viewmodel.validInput.bind(to: loginButton.isEnabled) viewmodel.onSuccess.subsribeNext { //Change to main screen } } } class LoginViewModel { //Input var username: Observable var password: Observable var didTapLogin: PublishSubject //Output var validInput: Observable(false) var loading: PublishSubject var onSuccess: PublishSubject var errors: PublishSubject var loginService: LoginService init() { combineLatest(username, password).map { TextUltis.notEmpty(username) && TextUltis.notEmpty(password) }.bind(to: validInput) didTapLogin.subscribeNext { loginService.login(username, password).subscribeNext { onSuccess.next() } } didTapLogin.flatMap { loginService.login(username, password) }.bind(to: onSuccess) } } class LoginService { func login(userName: String, password: String) -> Observable { return Observable.create { observer in observer.next() observer.completed() } } }