Проверка формы RxSwift и отправка запроса в одном потоке - PullRequest
1 голос
/ 02 февраля 2020

У меня есть случай, когда я хотел бы проверить форму, а затем, если все нормально go для запроса API.

Я написал некоторый код, и он работает нормально, но ошибки удаляют мой поток. Я знаю, что могу добавить ошибку .catch в конце плоской карты, но тогда будет выполнена следующая плоская карта.

Можно ли добавить ошибку перехвата в конце потока, не удаляя ее? Или единственный способ справиться с этим - отделить его от проверки двух потоков и ответов сервера?

        enum Response {
            case error(message: String)
            case success
        }

        let start = input.validate
            .withLatestFrom(input.textFields)
            .flatMap { [unowned self] fields -> Observable<String> in
                return self.validate(characters: fields)
            }
        .flatMapLatest { [unowned self] code -> Observable<String> in
            return self.apiClient.rxSendData(code)
                .retry(1)
        }
        .map { _ in return Response.success }
        .asDriver { Driver.just(Response.error(message: $0.localizedDescription)) }

Ответы [ 2 ]

1 голос
/ 06 февраля 2020

Рассматривали ли вы оператора materialize? Он преобразует наблюдаемую последовательность в наблюдаемую последовательность объектов событий, подробно описывающую то, что произошло, что не может привести к ошибке, но завершается после завершения входной последовательности. Затем вы можете поделиться этим.

Что-то вроде:

let code = input.validate
    .withLatestFrom(input.textFields)
    .flatMap { [unowned self] fields -> Observable<String> in
        self.validate(characters: fields)
            .materialize()
    }
    .share(replay: 1)

code
    .compactMap { $0.error }
    .subscribe() // Show error from `self.validate`
    .disposed(by: bag)

let request = code
    .compactMap { $0.element }
    // Will get to this flat map only if `self.validate` did not error
    .flatMapLatest { [unowned self] code -> Observable<String> in
        self.apiClient.rxSendData(code)
            .retry(1)
            .materialize()
    }
    .share(replay: 1)

request
    .compactMap { $0.error }
    .subscribe() // Show error from `self.apiClient.rxSendData`
    .disposed(by: bag)

request
    .compactMap { $0.element }
    // Do something as a result of the request being successful

Цепи не прекратятся при self.validate и self.apiClient.rxSendData испуская ошибки.

1 голос
/ 02 февраля 2020

Я делаю некоторые предположения о коде, который вы не показываете. Ваша функция validate особенно странна для меня. Похоже, что он выдает строку (которая игнорируется, если проверка прошла успешно и ничего не генерирует (или может быть ошибка), если проверка не удалась?

let start = input.validate
    .withLatestFrom(input.textFields)
    .flatMapLatest { [unowned self] fields -> Observable<String> in
        return self.validate(characters: fields)
            .catchError { _ in Observable.empty() } // empty() doesn't emit a value so the next flatMap won't be executed.
    }
    .flatMapLatest { [unowned self] _ -> Observable<Response> in
        return self.apiClient.rxSendData()
            .retry(1)
            .map { _ in Response.success }
            .catchError { error in Observable.just(Response.error(message: error.localizedDescription)) }
    }
    .asDriver { Driver.just(Response.error(message: $0.localizedDescription)) }

Если validate выдает ошибку при проверке) не удается, и вы хотите зафиксировать эту ошибку, тогда что-то вроде этого будет работать:

let start = input.validate
    .withLatestFrom(input.textFields)
    .flatMapLatest { [unowned self] fields -> Observable<Response> in
        return self.validate(characters: fields)
            .map { _ in Response.success }
            .catchError { Observable.just(Response.error(message: $0.localizedDescription)) }
    }
    .flatMapLatest { [unowned self] validation -> Observable<Response> in
        // here, the above flatMap emits a value no matter what, so we have to switch on it to determine if we want to continue or just push the Response down the pipe.
        switch validation {
            case .error:
                return Observable.just(validation)
            case .success:
                return self.apiClient.rxSendData()
                    .retry(1)
                    .map { _ in Response.success }
                    .catchError { error in Observable.just(Response.error(message: error.localizedDescription)) }
        }
    }
    .asDriver { Driver.just(Response.error(message: $0.localizedDescription)) }
...