使用 RxSwift 每 10 秒进行一次网络调用

Make a network call every 10 seconds with RxSwift

我对 RxSwift 完全陌生。我设法加载了我的 table 视图,但现在我想每 10 秒打一次电话。

我正在阅读 我可能应该使用 Observable<Int>.interval(10, scheduler: MainScheduler.instance),我试过但没有成功。

class MarketService: MarketServiceProtocol  {
    func fetchMarkets() -> Observable <[Market]> {
        return Observable.create { observer -> Disposable in
            RestManager.shared.makeRequest(withEndPoint: "market/v2/get-summary?region=US" , withHttpMethod: .get) { result in
                if let error = result.error {
                    observer.onError(error)
                    return
                }
                guard let response = result.response,
                      200 ... 299 ~= response.httpStatusCode else {
                    return
                }
                guard let data = result.data else {
                    return
                }
                do {
                    let decodedData = try JSONDecoder().decode(MarketResult.self, from: data)
                    observer.onNext(decodedData.marketSummaryAndSparkResponse.markets)
                } catch {
                    observer.onError(error)
                }
            }
            return Disposables.create { }
        }
    }
}

然后我调用我的视图控制器:

viewModel.fetchMarketViewModels().observe(on: MainScheduler.instance).bind(to: tableView.rx.items(cellIdentifier: HomeTableViewCell.cellIdentifier)) {
        index, viewModel, cell in
        guard let cell = cell as? HomeTableViewCell else { return }
        cell.setupData(viewModel: viewModel)
    }.disposed(by: self.disposableBag)

您的 Observable.create 关闭有几个问题。您必须确保在每个路径中都将某些内容发送到 observer,否则 Observable 将调用该函数然后不发出任何内容,您将不知道为什么。

此外,您还想尽量减少在传递给 create 的闭包中执行的逻辑量。你在那里做的太多了。

所以我们先把create闭包中的代码尽量简化一下:

extension RestManager {
    func rx_makeRequest(withEndPoint endPoint: String, withHttpMethod method: HttpMethod) -> Observable<(response: MyHTTPURLResponse, data: Data)> {
        Observable.create { observer in
            self.makeRequest(withEndPoint: endPoint, withHttpMethod: method) { result in
                if let response = result.response, let data = result.data {
                    observer.onNext((response, data))
                    observer.onCompleted()
                }
                else {
                    observer.onError(result.error ?? RxError.unknown)
                }
            }
            return Disposables.create() // is there some way of canceling a request? If so, it should be done here.
        }
    }
}

这是最低要求。仅包装底层回调,仅此而已。现在您的 fetchMarkets 调用更简单了:

class MarketService: MarketServiceProtocol  {
    func fetchMarkets() -> Observable <[Market]> {
        return RestManager.shared.rx_makeRequest(withEndPoint: "market/v2/get-summary?region=US", withHttpMethod: .get)
            .do(onNext: { result in
                guard 200...299 ~= result.response.httpStatusCode
                else { throw URLError.httpRequestFailed(response: result.response, data: result.data) }
            })
            .map { try JSONDecoder().decode(MarketResult.self, from: [=11=].data).marketSummaryAndSparkResponse.markets }
    }
}

现在谈谈你的问题。如何每 10 秒进行一次网络调用...只需将您的网络调用包装在一个 flatMap 中,如下所示:

Observable<Int>.interval(.seconds(10), scheduler: MainScheduler.instance)
    .flatMapLatest { _ in
        viewModel.fetchMarketViewModels()
    }
    .observe(on: MainScheduler.instance)
    .bind(to: tableView.rx.items(cellIdentifier: HomeTableViewCell.cellIdentifier)) { index, viewModel, cell in
        guard let cell = cell as? HomeTableViewCell else { return }
        cell.setupData(viewModel: viewModel)
    }
    .disposed(by: self.disposableBag)

this article 中了解有关 flatMap 及其变体的更多信息。