基于RxSwift+MVVM实现列表页数据自动刷新的方案咨询
RxSwift + MVVM 实现列表页自动更新的正确姿势
首先明确:在RxSwift的响应式逻辑里,别直接在viewWillAppear里硬写刷新代码,得用ViewModel的可观察序列来驱动,既符合MVVM的分工,也能让数据流更清晰。
具体实现步骤
1. 改造你的ViewModel
给ViewModel加一个用来触发刷新的PublishSubject,把数据请求和这个信号绑定,同时保留初始加载的逻辑:
import RxSwift import RxCocoa class WinningListViewModel { let disposeBag = DisposeBag() // 存储列表数据,供ViewController绑定UI let winningList = BehaviorRelay<[WinningModel]>(value: []) // 刷新触发信号,外部发送事件即可触发数据请求 let refreshTrigger = PublishSubject<Void>() init() { // 绑定刷新信号与数据请求逻辑 refreshTrigger .flatMapLatest { _ in // 你的数据请求方法,返回Observable类型 return store.getListEventWinning() .catch { error in // 处理请求失败场景,比如打印日志或返回空数组 print("拉取数据失败:\(error)") return Observable.just([]) } } .bind(to: winningList) .disposed(by: disposeBag) // 页面初始化时自动触发一次数据加载 refreshTrigger.onNext(()) } }
2. 在ViewController中绑定生命周期信号
利用RxSwift给UIViewController提供的rx.viewWillAppear信号,每次页面即将显示时,给ViewModel的refreshTrigger发送事件,触发数据刷新:
import RxSwift import RxCocoa class WinningListViewController: UIViewController { let disposeBag = DisposeBag() var viewModel: WinningListViewModel! @IBOutlet weak var tableView: UITableView! override func viewDidLoad() { super.viewDidLoad() setupBindings() } private func setupBindings() { // 将ViewModel的列表数据绑定到TableView viewModel.winningList .bind(to: tableView.rx.items(cellIdentifier: "WinningCell", cellType: WinningCell.self)) { index, model, cell in // 根据你的模型配置Cell内容 cell.titleLabel.text = model.title cell.descLabel.text = model.description } .disposed(by: disposeBag) // 绑定页面生命周期信号到ViewModel的刷新触发点 rx.viewWillAppear .map { _ in () } // 将事件转换为Void类型 .bind(to: viewModel.refreshTrigger) .disposed(by: disposeBag) } }
为什么这么做更靠谱?
- 符合响应式编程思路:所有数据更新都由可观察序列驱动,避免命令式的手动调用,逻辑更顺畅。
- 架构职责清晰:ViewModel负责数据的获取与管理,ViewController只处理UI绑定和生命周期事件传递,完全契合MVVM的设计原则。
- 自动处理返回刷新:从详情页返回列表页时,
viewWillAppear会自动触发,自然拉取最新数据,无需额外编写页面跳转回调逻辑。
额外优化建议
- 若担心频繁切换页面导致重复请求,可添加防抖处理:
refreshTrigger .debounce(.milliseconds(300), scheduler: MainScheduler.instance) .flatMapLatest { ... } - 可给ViewModel添加加载状态序列,用于控制加载动画的显示:
let isLoading = BehaviorRelay<Bool>(value: false) // 在请求前后更新加载状态 refreshTrigger .do(onNext: { _ in self.isLoading.accept(true) }) .flatMapLatest { ... } .do(onNext: { _ in self.isLoading.accept(false) }) .bind(to: winningList)
内容的提问来源于stack exchange,提问作者Tae Hun Yu
相关产品推荐
相关产品推荐

