Как преобразовать rx_tap UIButton в сетевой запрос напрямую, не отправляя запрос во вложенной подписке?

Предположим, у меня есть UIButton loginButton, я хочу отправить сетевой запрос, нажав кнопку со следующим кодом:

override func viewDidLoad() {
    super.viewDidLoad()

    let session = self.session // NSURLSession
    loginButton.rx_tap.subscribeNext { [unowned self] in
        session.rx_response(myRequest).subscribe { event in
            switch event {
            case .Next(let data, let response):
                // Handling Response
            case .Error(let error):
                // Handling Error
            default:
                return
            }
        }.addDisposableTo(disposeBag)
     }.addDisposableTo(disposeBag)
}

И в таком случае я могу повторно отправить запрос, нажав кнопку, даже если произошла ошибка с сетевым запросом.

Хотя код работает очень хорошо, я подумал, что это немного некрасиво из-за вложенной подписки. Я попробовал метод flatMap, чтобы сгладить подписку:

loginButton.rx_tap
    .flatMap {
        return session.rx_response(myRequest)
    }
    .subscribe { event in
        switch event {
        case .Next(let data, let response):
            print("Next")
        case .Error(let error):
            print(error)
        default:
            return
        }
     }
     .addDisposableTo(disposeBag)

Кажется, что два приведенных выше фрагмента имеют разную логику. Последняя подписка работает только при отсутствии ошибок, как и при обычной подписке, вместо подписки на сетевой запрос при каждом нажатии кнопки.

Есть ли способ сгладить формальный фрагмент?


Добавлен фрагмент вложенной подписки:

loginButton.rx_tap
    .debug("LoginButtonTapped")
    .subscribeNext {
        let disposable = session.rx_response(myRequest)
            .debug("AuthorizationRequest")
            .subscribe(
                onNext: { [unowned self] data, response in
                    // Handling Response
            },
                onError: { [unowned self] error in
                    // Showing Error
            })

        disposable.addDisposableTo(self.disposeBag)

        let alert = UIAlertController(title: "Please Wait.", message: "Requesting Tokens", preferredStyle: .Alert)
        alert.addAction(UIAlertAction(title: "Cancel", style: .Cancel) { _ in
            disposable.dispose()
            alert.dismissViewControllerAnimated(true, completion: nil)
        })
        self.presentViewController(alert, animated: true, completion: nil)
    }.addDisposableTo(disposeBag)

Отловить ошибку можно с помощью следующего кода:

let disposable = loginButton.rx_tap
    .map { session.rx_response(request) }
    .flatMap { [unowned self] in $0.catchError(self.presentError) }
    .subscribeNext { data, response in
        // Handling Response
    }

При необходимости мне также нужно отменить сетевой запрос. Если я вручную удалю disposable в приведенном выше фрагменте, подписка будет удалена, и я не смогу отправить запрос снова.


person mrahmiao    schedule 28.11.2015    source источник


Ответы (1)


У вас есть 2 способа добиться желаемого поведения. Первый - пользователю map, а затем switchLatest, это классический способ. Второй - пользователю flatMap, если вам нужно _4 _ / _ 5_ в последовательности сетевых запросов.

У Ash Furrow есть очень хороший пример в демонстрационный код семинара с использованием второго примера и Мойи:

    submitButton.rx_tap.map { _ -> Observable<MoyaResponse> in
        return provider.request(.Image)
    }.flatMap() { obs in
        return obs.filterSuccessfulStatusCodes()
            .mapImage()
            .catchError(self.presentError)
            .filter({ (thing) -> Bool in
                return thing != nil
            })
    }
    .take(1)
    .bindTo(imageView.rx_image)
    .addDisposableTo(disposeBag)

Кроме того, вы можете проверить пример на Github в репозиторий RxSwift, чтобы увидеть, как решаются подобные вещи.

person bontoJR    schedule 28.11.2015
comment
Обнаружена ошибка. И у меня есть еще одна проблема: отменить запрос, не избавившись от него. = = !!! - person mrahmiao; 28.11.2015