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

Swift Firebase单函数获取多组数据计数异常问题求助

解决Firebase获取数据时重复累加计数的问题

你遇到的问题核心非常明确:你把获取user-posts的请求放在了user-plan的子节点循环里。也就是说,每遍历一个user-plan的条目,就会发起一次user-posts的数据请求,每次请求到数据后又把所有post的key追加到totalPosts数组中——最终totalPosts的长度就是14×18=252,完全符合你看到的结果。

下面给你两种解决方案,根据你是否需要保存节点key来选择:


方案一:仅需要计数(不需要保存节点key)

这种情况最简洁,直接用Firebase的childrenCount属性获取条目数量,不需要遍历子节点:

func firebaseRetrieve() { 
    guard let uid = Auth.auth().currentUser?.uid else {return} 
    
    // 第一步:获取user-plan的条目数量
    let planRef = DB_BASE.child("user-plan").child(uid) 
    planRef.observeSingleEvent(of: .value, with: { [weak self] planSnapshot in 
        guard let self = self else { return }
        
        let planCount = Double(planSnapshot.childrenCount)
        // 处理plan数量为0的情况,避免除以0崩溃
        guard planCount > 0 else {
            self.fraction = 0
            // 这里调用更新进度条的函数
            return
        }
        
        // 第二步:获取user-posts的条目数量(仅请求一次)
        let postRef = DB_BASE.child("user-posts").child(uid) 
        postRef.observeSingleEvent(of: .value, with: { [weak self] postSnapshot in 
            guard let self = self else { return }
            
            let postCount = Double(postSnapshot.childrenCount)
            self.fraction = postCount / planCount
            // 此处传入另一个函数,用fraction值更新进度条
        })
    }) 
}

改进点说明:

  • 去掉了冗余的子节点遍历,用childrenCount直接获取数量,代码更高效
  • 将user-posts的请求移到user-plan数据获取完成的回调外层,只请求一次,彻底避免重复累加
  • 增加[weak self]避免循环引用,符合Swift内存管理规范
  • 增加了plan数量为0的边界处理,防止运行时崩溃

方案二:需要保存节点key(比如后续要用到这些key)

如果你必须保存user-plan和user-posts的节点key,那可以先完整收集完plan的key,再去收集posts的key,确保posts只被收集一次:

func firebaseRetrieve() { 
    guard let uid = Auth.auth().currentUser?.uid else {return} 
    var tempPlans: [String] = []
    var tempPosts: [String] = []
    
    // 第一步:收集所有user-plan的key
    let planRef = DB_BASE.child("user-plan").child(uid) 
    planRef.observeSingleEvent(of: .value, with: { [weak self] planSnapshot in 
        guard let self = self else { return }
        
        for child in planSnapshot.children {
            if let snap = child as? DataSnapshot {
                tempPlans.append(snap.key)
            }
        }
        
        let planCount = Double(tempPlans.count)
        guard planCount > 0 else {
            self.fraction = 0
            // 更新进度条
            return
        }
        
        // 第二步:收集所有user-posts的key(仅收集一次)
        let postRef = DB_BASE.child("user-posts").child(uid) 
        postRef.observeSingleEvent(of: .value, with: { [weak self] postSnapshot in 
            guard let self = self else { return }
            
            for child in postSnapshot.children {
                if let snaps = child as? DataSnapshot {
                    tempPosts.append(snaps.key)
                }
            }
            
            let postCount = Double(tempPosts.count)
            self.fraction = postCount / planCount
            // 更新进度条
            // 把临时数组赋值给实例变量(如果需要的话)
            self.totalPlans = tempPlans
            self.totalPosts = tempPosts
        })
    }) 
}

改进点说明:

  • 用临时数组先收集完所有plan的key,再去请求posts数据
  • posts的key仅被收集一次,不会因为plan的数量重复累加
  • 同样处理了边界情况和内存引用问题

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 04:41:58