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

选择CategoryVc单元格返回MainVc,CollectionView无法刷新Firebase数据

问题分析与解决方案

首先,我看到你遇到的核心问题是:从CategoryVc pop回MainVc后,UICollectionView没有加载新选中分类的Firebase数据,只有App启动时能正常加载。结合你的代码,我发现几个关键问题:


1. 静态变量混淆导致取值错误

你在MainVc中定义了静态变量chosenCategory,但在fetchQuotes和refresh方法里却使用了QuoteCell.chosenCategory,而CategoryVc中修改的也是QuoteCell.chosenCategory。这就导致MainVc的fetchQuotes始终读取的是MainVc.chosenCategory的初始值("General"),完全没用到你选中的新分类!

修复步骤:

统一所有引用到同一个静态变量,比如全部使用MainVc.chosenCategory:

修改MainVc代码:

// 保持静态变量定义
static var chosenCategory = "General"

func fetchQuotes() {
    // 替换QuoteCell.chosenCategory为MainVc.chosenCategory
    CATEGORIES_REF.child(MainVc.chosenCategory).observe(.childAdded) { (snapshot) in
        let quoteId = snapshot.key
        // 这里同样替换
        CATEGORIES_REF.child(MainVc.chosenCategory).child(quoteId).observeSingleEvent(of: .value, with: { (snapshot) in
            guard let dictionary = snapshot.value as? Dictionary<String, AnyObject> else { return }
            let quote = Quote(quoteId: quoteId, dictionary: dictionary)
            self.quotes.append(quote)
            // 必须在主线程刷新UI
            DispatchQueue.main.async {
                self.collectionView.reloadData()
            }
            print("second: \(MainVc.chosenCategory)")
        })
    }
}

func refresh() {
    quotes.removeAll()
    // 先清空UI
    DispatchQueue.main.async {
        self.collectionView.reloadData()
    }
    fetchQuotes()
    print(MainVc.chosenCategory)
}

修改CategoryVc代码:

override func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
    // 修改为MainVc的静态变量
    MainVc.chosenCategory = "\(categories[indexPath.item])"
    self.navigationController?.popViewController(animated: true)
}

2. 刷新时机错误 + 实例引用问题

你在CategoryVc中先pop再调用quoteCell.refresh(),这里有两个问题:

  • pop是异步操作,执行时MainVc还没回到前台,此时调用refresh可能无法正确触发UI更新
  • quoteCell的引用可能不是当前MainVc中正在显示的cell实例,导致refresh调用无效

解决方案:利用viewDidAppear触发刷新

在MainVc中监听视图出现的时机,检查分类是否变化,自动触发刷新:

MainVc中添加代码:

// 记录上次选中的分类,用于对比变化
private var lastSelectedCategory = MainVc.chosenCategory

override func viewDidAppear(_ animated: Bool) {
    super.viewDidAppear(animated)
    // 如果分类发生变化,执行刷新
    if lastSelectedCategory != MainVc.chosenCategory {
        lastSelectedCategory = MainVc.chosenCategory
        refresh()
    }
}

这样,当从CategoryVc pop回来时,MainVc的viewDidAppear会被调用,自动检查分类是否更新并刷新数据,完全不需要在CategoryVc中直接调用refresh。


3. Firebase监听未移除导致重复数据(额外优化)

你的fetchQuotes使用了observe(.childAdded),这是一个持续的监听。如果多次调用refresh,旧的监听不会自动移除,会导致重复添加数据到quotes数组中。

优化步骤:保存监听句柄并在刷新时移除

// 保存Firebase监听的句柄
private var childAddedListenerHandle: DatabaseHandle?

func fetchQuotes() {
    // 先移除之前的监听(如果存在)
    if let handle = childAddedListenerHandle {
        CATEGORIES_REF.child(MainVc.chosenCategory).removeObserver(withHandle: handle)
    }
    // 添加新的监听
    childAddedListenerHandle = CATEGORIES_REF.child(MainVc.chosenCategory).observe(.childAdded) { (snapshot) in
        let quoteId = snapshot.key
        CATEGORIES_REF.child(MainVc.chosenCategory).child(quoteId).observeSingleEvent(of: .value, with: { (snapshot) in
            guard let dictionary = snapshot.value as? Dictionary<String, AnyObject> else { return }
            let quote = Quote(quoteId: quoteId, dictionary: dictionary)
            self.quotes.append(quote)
            DispatchQueue.main.async {
                self.collectionView.reloadData()
            }
            print("second: \(MainVc.chosenCategory)")
        })
    }
}

这样每次刷新都会先清除旧的监听,避免重复数据。


按照以上步骤修改后,应该就能解决pop回MainVc后不加载新分类数据的问题了。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.14 07:42:38