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

如何清空TableView并重新加载数据?解决重复显示问题

解决CollectionView重复显示数据的问题

我帮你分析下问题所在,然后给出具体的修复方案:

问题根源

你现在遇到的重复显示问题,主要来自两个点:

  1. 重复绑定Firebase监听:每次点击按钮调用getWallpaperFromDB()时,都会新增一个childAdded类型的持续观察者——之前的监听并没有被移除,所以后续只要有数据触发,所有存在的观察者都会执行闭包,导致数据被多次添加到数组里。
  2. 数据源未清空:每次调用函数时,你直接往wallpapers数组追加新数据,旧数据还留在数组里,自然会导致CollectionView重复渲染。

解决方案

针对这两个问题,我给你两种不同场景的修复方案:

场景一:只需要一次性加载数据(不需要实时监听更新)

如果你的需求是点击按钮后一次性拉取所有壁纸数据,不需要实时监听数据库的新增内容,可以改用observeSingleEvent单次监听,同时每次加载前清空数据源:

func getWallpaperFromDB() {
    let databaseRef = Database.database().reference()
    
    // 先清空数据源,避免旧数据残留
    self.wallpapers.removeAll()
    
    // 使用单次监听获取所有壁纸数据
    databaseRef.child("wallpapers").observeSingleEvent(of: .value) { snapshot in
        // 遍历所有子节点解析数据
        for childSnapshot in snapshot.children {
            guard let childSnap = childSnapshot as? DataSnapshot,
                  let value = childSnap.value as? [String: Any],
                  let categoryID = value["categoryID"] as? String,
                  let categoryName = value["categoryName"] as? String,
                  let wallpaperName = value["wallpaperName"] as? String else {
                // 数据格式异常时跳过该节点,避免崩溃
                continue
            }
            
            let wallpaperId = childSnap.key
            let dbWallpaper = Wallpaper(categoryID: categoryID, categoryName: categoryName, wallpaperId: wallpaperId, wallpaperName: wallpaperName)
            self.wallpapers.append(dbWallpaper)
        }
        
        // 遍历完成后统一刷新CollectionView
        self.collectionViewTable.reloadData()
    }
}

@IBAction func slideMenuButton(_ sender: Any) {
    getWallpaperFromDB()
}

场景二:需要实时监听数据库的新增数据

如果你需要持续监听数据库里的新增壁纸,那么需要管理好观察者的引用,避免重复绑定:

首先在类中添加一个观察者引用属性:

// 保存壁纸监听的引用,用于后续移除
var wallpaperObserver: DatabaseHandle?

然后修改getWallpaperFromDB()函数:

func getWallpaperFromDB() {
    let databaseRef = Database.database().reference().child("wallpapers")
    
    // 移除旧的监听(如果存在),避免重复触发
    if let observer = wallpaperObserver {
        databaseRef.removeObserver(withHandle: observer)
    }
    
    // 清空数据源,重新加载
    self.wallpapers.removeAll()
    
    // 绑定新的监听并保存引用
    wallpaperObserver = databaseRef.observe(DataEventType.childAdded) { snapshot in
        guard let value = snapshot.value as? [String: Any],
              let categoryID = value["categoryID"] as? String,
              let categoryName = value["categoryName"] as? String,
              let wallpaperName = value["wallpaperName"] as? String else {
            return
        }
        
        let wallpaperId = snapshot.key
        let dbWallpaper = Wallpaper(categoryID: categoryID, categoryName: categoryName, wallpaperId: wallpaperId, wallpaperName: wallpaperName)
        self.wallpapers.append(dbWallpaper)
        self.collectionViewTable.reloadData()
    }
}

@IBAction func slideMenuButton(_ sender: Any) {
    getWallpaperFromDB()
}

另外补充个小建议:把代码里的强制解包(as!)换成可选绑定,能避免因为数据库数据格式异常导致的崩溃,就像上面代码里写的那样。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.29 07:36:55