How to transform rx_tap of UIButton to a network request directly without sending the request in a nested subscribe?

别等时光非礼了梦想. 提交于 2020-01-23 03:58:32

问题


Suppose that I have a UIButton loginButton, I want to send a network request while tapping the button with the following code:

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)
}

And in such case I can resend the request by tapping the button even if an error occurred with the network request.

Although the code works very well, I thought it is a little bit ugly due to the nested subscription. I tried the flatMap method to flatten the subscription:

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)

It seems that the two snippets above are of different logic. The latter subscription only works while no error happened just like normal subscription rather than subscribe the network request every time the button has been tapped.

Is there any way to flatten the formal snippet?


Added a snippet of nested subscription:

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)

Error can be caught using the following code:

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

I also need to cancel the network request if necessary. If I manually dispose the disposable in the above snippet, the subscription will be disposed and I can not send the request again.


回答1:


You have 2 ways to achieve the requested behaviour. The first one is to user map and then switchLatest, this is the classic way. The second one is to user flatMap if you need to catch/retry in the network request sequence.

Ash Furrow has a very nice example in a workshop demo code using the second example and Moya:

    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)

Alternatively, you can check the Github example in the RxSwift repository to see how these sort of things are handled.



来源:https://stackoverflow.com/questions/33968378/how-to-transform-rx-tap-of-uibutton-to-a-network-request-directly-without-sendin

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!