You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

RxSwift中等待多API完成后刷新UITableView问题求助

解决RxSwift双API请求后仅刷新一次UITableView的问题

你遇到的「Done打印两次」问题,核心原因大概率是Observable被重复订阅,或是其中某个API请求的Observable本身多次发射事件。以下是针对性的解决方案:

一、先确保API请求是单次发射事件

首先确认你的API请求Observable是单次触发的(即完成后仅发送一个next事件,随后completed)。封装API请求的方法应类似这样:

func fetchFirstData() -> Observable<[FirstModel]> {
    return URLSession.shared.rx.data(request: firstApiRequest)
        .map { data in
            try JSONDecoder().decode([FirstModel].self, from: data)
        }
        .asObservable()
}

func fetchSecondData() -> Observable<[SecondModel]> {
    return URLSession.shared.rx.data(request: secondApiRequest)
        .map { data in
            try JSONDecoder().decode([SecondModel].self, from: data)
        }
        .asObservable()
}

二、用Observable.zip实现单次触发(正确写法)

zip的特性是严格等待每个Observable各发射一次事件后,才合并触发一次,完全匹配你的需求。如果之前用zip仍触发多次,检查是否重复订阅了该序列。正确示例:

// 合并两个API请求
Observable.zip(fetchFirstData(), fetchSecondData())
    .subscribe(onNext: { firstData, secondData in
        // 合并数据到数据源
        self.dataSource = firstData + secondData
        // 仅刷新一次TableView
        self.tableView.reloadData()
        print("Done")
    }, onError: { error in
        print("请求失败:\(error.localizedDescription)")
    })
    .disposed(by: disposeBag) // 必须添加到disposeBag避免内存泄漏

三、排查重复订阅的常见场景

如果仍出现两次打印,检查以下几点:

  • 是否在多个生命周期方法(比如viewDidLoad和viewWillAppear)中重复订阅了同一个合并序列?
  • 是否每次调用API方法都会创建新请求,且你无意中调用了两次?
  • 如果Observable是热序列,添加.share(replay: 1, scope: .whileConnected)确保共享订阅,避免重复触发。

四、语义化替代方案:Single.zip

API请求通常是「单次成功/失败」,用Single更贴合场景,Single.zip只会在两个请求都成功后触发一次:

// 将API请求改为Single类型
func fetchFirstData() -> Single<[FirstModel]> {
    return URLSession.shared.rx.data(request: firstApiRequest)
        .map { try JSONDecoder().decode([FirstModel].self, from: $0) }
        .asSingle()
}

func fetchSecondData() -> Single<[SecondModel]> {
    return URLSession.shared.rx.data(request: secondApiRequest)
        .map { try JSONDecoder().decode([SecondModel].self, from: $0) }
        .asSingle()
}

// 合并订阅
Single.zip(fetchFirstData(), fetchSecondData())
    .subscribe(onSuccess: { firstData, secondData in
        self.dataSource = firstData + secondData
        self.tableView.reloadData()
        print("Done")
    }, onFailure: { error in
        print("请求失败:\(error)")
    })
    .disposed(by: disposeBag)

内容的提问来源于stack exchange,提问作者cMoNz

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.09 21:01:39