Создание действия на основе наблюдаемого - PullRequest
0 голосов
/ 14 апреля 2019

Я пишу свое первое приложение на основе 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)
    }
...