1

假设我有一个 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,订阅将被处理,我无法再次发送请求。

4

1 回答 1

2

您有 2 种方法来实现所请求的行为。第一个是用户map然后switchLatest,这是经典的方式。第二个是用户flatMap如果需要catch/retry在网络请求序列中。

Ash Furrow 在使用第二个示例和 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)

或者,您可以查看RxSwift 存储库中的 Github 示例,了解这些事情是如何处理的。

于 2015-11-28T11:30:50.683 回答