假设我有一个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
,则订阅将被处理,并且我无法再次发送请求。 最佳答案
您有2种方法来实现要求的行为。第一个是先使用map
,然后再使用switchLatest
,这是经典的方式。第二个是如果需要在网络请求序列中使用flatMap
/ catch
,则使用retry
。
Ash Furrow使用第二个示例和Moya在workshop demo code中有一个非常好的示例:
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 example in the RxSwift repository以查看如何处理这些事情。