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

Swift中TableView双数据源的正确实现方法求助

问题根源分析

你的代码存在两个核心问题导致TableView无法刷新:

  1. 错误创建新的ViewController实例:在CategoryViewController的点击方法中,你新建了一个SearchViewController对象,调用它的fetchCategoryData方法后,数据更新的是这个从未显示的新实例,而非当前界面上正在展示的那个SearchViewController。
  2. 数据源赋值错误:在fetchData方法中,你尝试将数组myData直接赋值给tableView.dataSource,但数组并不实现UITableViewDataSource协议,这是无效操作,会导致数据源逻辑混乱。

解决方案及代码修正

1. 修正SearchViewController的数据源实现

让SearchViewController自身实现UITableViewDataSource协议,通过内部数组catsModel管理数据,而非直接给tableView.dataSource赋值数组。

class SearchViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
    @IBOutlet weak var tableView: UITableView!
    var catsModel: [CatModel] = []
    
    override func viewDidLoad() {
        super.viewDidLoad()
        // 初始化时设置数据源和代理为自身
        tableView.dataSource = self
        tableView.delegate = self
        // 加载全部数据
        fetchData()
    }
    
    // 获取全部猫咪图片(修正后)
    func fetchData() {
        guard var endPoint = // 你的endpoint配置 else { return }

        endPoint.queryItems = queryParameters.map({ (key, value) in
            URLQueryItem(name: key, value: value)
        })

        guard let url = endPoint.url else {
            return
        }

        var request = URLRequest(url: url)
        request.setValue(ApiClient.Identifiers.apiKey, forHTTPHeaderField: "x-api-key")

        let task = URLSession.shared.dataTask(with: request) { data, response, error in
            DispatchQueue.main.async {
                if let error = error {
                    print(error.debugDescription)
                    return
                }
                guard let data = data else {
                    print("未获取到数据")
                    return
                }
                do {
                    let myData = try JSONDecoder().decode([CatModel].self, from: data)
                    self.catsModel = myData
                    self.tableView.reloadData()
                } catch let error {
                    print(error)
                }
            }
        }
        task.resume()
    }
    
    // 按分类ID筛选数据(修正后)
    func fetchCategoryData(categoryID: Int) {
        var endpoint = URLComponents()
        // 补全你的URL配置(scheme、host、path等)
        endpoint.queryItems = [URLQueryItem(name: "category_id", value: "\(categoryID)")]
        
        guard let url = endpoint.url else {
            return
        }
        var request = URLRequest(url: url)
        request.setValue(ApiClient.Identifiers.apiKey, forHTTPHeaderField: "x-api-key")

        let task = URLSession.shared.dataTask(with: request) { data, response, error in
            DispatchQueue.main.async {
                if let error = error {
                    print(error.debugDescription)
                    return
                }
                guard let data = data else {
                    print("未获取到数据")
                    return
                }
                do {
                    let myData = try JSONDecoder().decode([CatModel].self, from: data)
                    self.catsModel = myData
                    self.tableView.reloadData()
                } catch let error {
                    print(error)
                }
            }
        }
        task.resume()
    }
    
    // MARK: UITableViewDataSource 实现
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return catsModel.count
    }
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        // 替换为你的Cell标识符和自定义Cell类
        let cell = tableView.dequeueReusableCell(withIdentifier: "CatCell", for: indexPath) as! CatTableViewCell
        let cat = catsModel[indexPath.row]
        // 根据CatModel配置Cell内容(示例)
        // cell.catNameLabel.text = cat.name
        // cell.catImageView.kf.setImage(with: URL(string: cat.imageUrl))
        return cell
    }
}

2. 修正CategoryViewController的分类点击逻辑

根据你的页面跳转场景,选择以下两种方式之一:

场景A:从CategoryViewController跳转到新的SearchViewController

直接创建实例并传入分类ID后跳转:

func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
    let cat = catsModel[indexPath.row]
    let searchVC = SearchViewController()
    searchVC.fetchCategoryData(categoryID: cat.id)
    navigationController?.pushViewController(searchVC, animated: true)
}

场景B:SearchViewController已在导航栈中(从Search跳转到Category后返回)

用闭包回调传递分类ID,更新原SearchViewController的数据:

// CategoryViewController中添加闭包属性
class CategoryViewController: UIViewController, UICollectionViewDataSource {
    var onCategorySelected: ((Int) -> Void)?
    var catsModel: [CategoryModel] = []
    
    // ...其他代码
    
    func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
        let cat = catsModel[indexPath.row]
        // 触发回调传递分类ID
        onCategorySelected?(cat.id)
        navigationController?.popViewController(animated: true)
    }
}

// SearchViewController中跳转到Category时设置闭包
func showCategoryPage() {
    let categoryVC = CategoryViewController()
    categoryVC.onCategorySelected = { [weak self] categoryID in
        self?.fetchCategoryData(categoryID: categoryID)
    }
    navigationController?.pushViewController(categoryVC, animated: true)
}

额外注意事项
  • 确保TableView的Cell标识符与代码中dequeueReusableCell的标识符完全一致
  • 网络请求中避免强制解包data!,改用guard let做安全判断
  • 若使用自定义Cell,需确保Cell类已正确关联XIB或Storyboard

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.11 08:20:27