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

使用MVVM模式时TableView请求API后不刷新数据该如何解决

iOS GEODb API对接TableView不更新问题排查及解决方案

核心问题定位

  • 在cellForRowAt中调用reloadData属于逻辑错误:cellForRowAt是TableView渲染单元格时触发的数据源回调,在此处调用刷新方法会触发「重新请求数据源→调用cellForRowAt→再次触发刷新」的死循环,最终会导致TableView布局计算异常、甚至直接消失。
  • UI刷新未在主线程执行:API请求默认在后台线程回调,就算成功拿到数据、直接执行刷新操作也不会生效,iOS所有UI相关操作必须强制在主线程执行。
  • MVVM数据变更通知缺失:ViewModel拿到接口数据更新列表后,没有主动通知ViewController触发TableView刷新,TableView的数据源没有更新,自然不会渲染新内容。
  • 其他可能的低级问题:未给TableView绑定dataSource/delegate、cell复用标识符写错、单元格赋值时取错数组下标导致内容为空。

修复步骤

  1. 首先删除所有在cellForRowAt方法中调用reloadData的代码,该方法仅负责根据当前数据源配置单元格内容即可。
  2. 在ViewModel中新增数据变更回调,数据更新后主动通知ViewController
  3. ViewController收到更新通知后,切主线程执行TableView刷新操作

代码示例

ViewModel层逻辑

// 定义数据变更回调
var countriesDidUpdate: (() -> Void)?
// 国家列表数据源
var countries: [CountryModel] = [] {
    didSet {
        // 数据赋值后自动触发回调
        countriesDidUpdate?()
    }
}

// 发起GEODb API请求
func requestCountryList() {
    // 你的GEODb Rapid API请求逻辑
    GEODbAPIManager.shared.fetchCountries { [weak self] result in
        guard let self = self else { return }
        switch result {
        case .success(let list):
            // 赋值时自动触发didSet回调
            self.countries = list
            // 你当前已经可以正常打印该列表
            print(list)
        case .failure(let error):
            print(error.localizedDescription)
        }
    }
}

ViewController层逻辑

override func viewDidLoad() {
    super.viewDidLoad()
    // 绑定TableView数据源和代理
    tableView.dataSource = self
    tableView.delegate = self
    // 注册单元格
    tableView.register(UITableViewCell.self, forCellReuseIdentifier: "CountryCell")
    
    // 绑定ViewModel数据变更回调
    viewModel.countriesDidUpdate = { [weak self] in
        // 强制切主线程执行UI刷新
        DispatchQueue.main.async {
            self?.tableView.reloadData()
        }
    }
    
    // 发起请求
    viewModel.requestCountryList()
}

// MARK: - TableView数据源方法
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return viewModel.countries.count
}

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: "CountryCell", for: indexPath)
    // 直接从ViewModel数据源取值赋值即可
    cell.textLabel?.text = viewModel.countries[indexPath.row].name
    return cell
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.24 19:06:00