Я пишу свое первое приложение на основе MVVM и экспериментирую с Actions, чтобы я мог использовать некоторые из их встроенных функций, которые могли бы показаться полезными. Однако мне трудно разобраться, как определить Action, который зависит от частного ReplaySubject (позволяет мне «кормить» модель представления) и привязан к значению в текстовом поле в контроллере представления. Я, вероятно, не слишком хорошо объясняю себя, но, надеюсь, код прояснит, что я пытаюсь сделать. Кажется, я не могу найти много примеров использования Action, поэтому указатели были бы очень полезны
// View model
protocol ObservationViewModelType: ViewModelType { }
final class ObservationsViewModel: ObservationViewModelType {
// MARK:- Protocol conformance
typealias Dependencies = HasSceneCoordinator & HasPatientService
struct Input {
// var patient: AnyObserver<Patient>
}
struct Output {
let name: Driver<String>
let created: Driver<String>
let checked: Driver<String>
}
struct Actions {
let addObservation: (Observable<Patient>) -> Action<String, Void>
}
// MARK:- Public interface
let input: Input
let output: Output
lazy var action = Actions(addObservation: self.addObservation)
// MARK:- Private properties
private let dependencies: Dependencies
private let patientSubject = ReplaySubject<Patient>.create(bufferSize: 1)
private let patient: BehaviorRelay<Patient>
private let disposeBag = DisposeBag()
// MARK:- Initialiser
init(dependencies: Dependencies) {
self.dependencies = dependencies
let patientName = patientSubject
.flatMap { patient in // have to flatMap otherwise you get Observable<Observable<String>>!
return patient.rx.observe(String.self, "name")
}
.flatMap { $0 == nil ? Observable.empty() : Observable.just($0!) }
.asDriver(onErrorJustReturn: "ERROR")
let patientCreated = patientSubject
.flatMap { patient in
return patient.rx.observe(Date.self, "created")
}
.map { Utilities.createFormattedStringFrom(date: $0)}
.asDriver(onErrorJustReturn: "ERROR")
let patientChecked = patientSubject
.flatMap { patient in
return patient.rx.observe(Date.self, "checked")
}
.map { Utilities.createFormattedStringFrom(date: $0)}
.asDriver(onErrorJustReturn: "ERROR")
self.input = Input() // No inputs from viewController in this instance
self.output = Output(name: patientName, created: patientCreated, checked: patientChecked)
}
// MARK:- Actions
private lazy var addObservation: (Observable<Patient>) -> Action<String, Void> = { [unowned self] patient in
return Action { text in
patient.subscribe(onNext: { patient in
return self.dependencies.patientService.addObservation(patient: patient, text: text).map { _ in }
}
.disposed(by: self.disposeBag)
)}(self.patient.asObservable())
}
}
// View controller binding method
func bindViewModel() {
viewModel.output.name
.drive(nameLabel.rx.text)
.disposed(by: disposeBag)
viewModel.output.created
.drive(createdLabel.rx.text)
.disposed(by: disposeBag)
viewModel.output.checked
.drive(checkedLabel.rx.text)
.disposed(by: disposeBag)
addObservationButton.rx.tap
.withLatestFrom(observationTextField.rx.text.orEmpty)
.subscribe(viewModel.action.addObservation.inputs)
.disposed(by: disposeBag)
}