选择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

