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.