如何将 UIButton 的 rx_tap 直接转换为网络请求,而不在嵌套订阅中发送请求?
Posted
技术标签:
【中文标题】如何将 UIButton 的 rx_tap 直接转换为网络请求,而不在嵌套订阅中发送请求?【英文标题】:How to transform rx_tap of UIButton to a network request directly without sending the request in a nested subscribe? 【发布时间】:2015-11-28 06:22:43 【问题描述】:假设我有一个 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)
好像上面的两个sn-ps的逻辑不同。后一种订阅仅在没有错误发生时才有效,就像正常订阅一样,而不是每次点击按钮时都订阅网络请求。
有没有办法把正式的sn-p弄平?
添加了嵌套订阅的sn-p:
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
如有必要,我还需要取消网络请求。如果我在上面的sn-p中手动dispose disposable
,订阅就会被dispose,我无法再次发送请求。
【问题讨论】:
【参考方案1】:您有 2 种方法来实现所请求的行为。第一个是用户map
,然后是switchLatest
,这是经典的方式。第二个是用户flatMap
,如果你需要在网络请求序列中catch
/retry
。
Ash Furrow 在workshop demo code 中有一个非常好的示例,使用第二个示例和 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)
或者,您可以查看Github example in the RxSwift repository 了解如何处理这些事情。
【讨论】:
已发现错误。我还有另一个问题:取消请求而不处置它。 = =!!!以上是关于如何将 UIButton 的 rx_tap 直接转换为网络请求,而不在嵌套订阅中发送请求?的主要内容,如果未能解决你的问题,请参考以下文章