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

iOS双Tab应用点击Home页TableView收藏后Saved页数据不累积问题求助

问题根因

你的猜测正确,核心问题是每次给cell设置saveButtonDelegate时,都重新创建了SavedViewController的新实例,而非使用TabBar中已经存在的同一个SavedViewController实例。每个新实例的countryDataArray都是空的初始状态,所以每次追加数据都只会往新实例的数组存储当前点击的国家,无法实现数据累积。
除此之外你当前的逻辑还存在两个隐藏问题:

  • 仅实现了新增收藏逻辑,没有处理取消收藏场景
  • cell复用场景下没有重置星标状态,会出现显示和实际收藏状态不一致的错乱问题

解决方法

方案1:全局收藏状态单独维护全局收藏数据(最推荐,耦合性低易扩展)

收藏数据属于全局状态,不应该绑定在某个ViewController实例上,建议单独封装一个全局收藏管理类维护统一的收藏数组,所有页面都访问同一份数据即可。

  1. 实现全局收藏管理类:
// 全局收藏管理类
class FavoritesManager {
    static let shared = FavoritesManager()
    private init() {
        // 可选:启动时读取本地持久化的收藏数据
        if let data = UserDefaults.standard.data(forKey: "FavoriteCountries"), 
           let list = try? JSONDecoder().decode([CountryData].self, from: data) {
            favoriteCountries = list
        }
    }
    // 全局统一的收藏数组
    var favoriteCountries: [CountryData] = [] {
        didSet {
            // 可选:收藏变化时自动持久化到本地,App重启后数据不丢失
            if let data = try? JSONEncoder().encode(favoriteCountries) {
                UserDefaults.standard.set(data, forKey: "FavoriteCountries")
            }
        }
    }
    
    // 切换收藏状态
    func toggleFavorite(country: CountryData) {
        if let index = favoriteCountries.firstIndex(where: { $0.name == country.name }) {
            favoriteCountries.remove(at: index)
        } else {
            favoriteCountries.append(country)
        }
    }
    
    // 判断当前国家是否已收藏
    func isFavorited(country: CountryData) -> Bool {
        return favoriteCountries.contains(where: { $0.name == country.name })
    }
}
  1. 修改cell按钮点击逻辑,不再代理给SavedViewController,直接调用全局管理类:
@objc func buttonTapped() {
    let currentIsFavorited = FavoritesManager.shared.isFavorited(country: countryData)
    // 切换收藏状态
    FavoritesManager.shared.toggleFavorite(country: countryData)
    // 更新按钮UI
    let image = currentIsFavorited ? UIImage(systemName: "star") : UIImage(systemName: "star.fill")
    saveButton.setImage(image, for: .normal)
    isSaveButtonSelected = !currentIsFavorited
    // 发送通知通知收藏列表页刷新
    NotificationCenter.default.post(name: NSNotification.Name("FavoritesUpdated"), object: nil)
}
  1. 在SavedViewController监听通知刷新列表,同时每次页面展示时同步最新数据:
class SavedViewController: UIViewController {
    var countryDataArray: [CountryData] = []
    
    override func viewDidLoad() {
        super.viewDidLoad()
        // 监听收藏变化通知
        NotificationCenter.default.addObserver(self, selector: #selector(refreshFavoritesList), name: NSNotification.Name("FavoritesUpdated"), object: nil)
    }
    
    // 每次切换到Saved页时同步最新收藏数据
    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        refreshFavoritesList()
    }
    
    @objc private func refreshFavoritesList() {
        countryDataArray = FavoritesManager.shared.favoriteCountries
        DispatchQueue.main.async {
            self.countriesTableView.reloadData()
        }
    }
}
  1. 在Home页的cellForRowAt方法中补充cell复用的星标状态赋值,避免复用错乱:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: "CountriesTableViewCell", for: indexPath) as! CountriesTableViewCell
    let currentCountry = 你的首页数据源[indexPath.row]
    cell.countryData = currentCountry
    // 根据实际收藏状态设置按钮UI
    let isFavorited = FavoritesManager.shared.isFavorited(country: currentCountry)
    cell.isSaveButtonSelected = isFavorited
    cell.saveButton.setImage(isFavorited ? UIImage(systemName: "star.fill") : UIImage(systemName: "star"), for: .normal)
    return cell
}

方案2:复用TabBar中已存在的SavedViewController实例(不推荐,耦合性高)

如果不想调整现有代理架构,可以在Home页给cell设置delegate时,从TabBar的已加载的控制器数组中找到已经初始化完成的SavedViewController实例,保证所有cell的代理指向同一个实例即可:

// Home页的cellForRowAt方法中
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: "CountriesTableViewCell", for: indexPath) as! CountriesTableViewCell
    let currentCountry = 你的首页数据源[indexPath.row]
    cell.countryData = currentCountry
    // 找到TabBar中已经存在的SavedViewController实例
    if let savedVC = self.tabBarController?.viewControllers?.first(where: { $0 is SavedViewController }) as? SavedViewController {
        cell.saveButtonDelegate = savedVC
        // 同步星标状态避免复用错乱
        let isFavorited = savedVC.countryDataArray.contains(where: { $0.name == currentCountry.name })
        cell.isSaveButtonSelected = isFavorited
        cell.saveButton.setImage(isFavorited ? UIImage(systemName: "star.fill") : UIImage(systemName: "star"), for: .normal)
    }
    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 21:24:08