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

如何正确调用DispatchGroup?Firebase多标签UID聚合后执行函数

解决DispatchGroup配合Firebase异步请求的问题

你的问题核心是没把DispatchGroup的enter()和leave()和Firebase的异步请求正确绑定起来——因为Firebase的observe(.value)是异步执行的,forEach循环会快速走完所有迭代,但每个请求的回调是独立触发的,之前的写法没把这些异步任务纳入DispatchGroup的管理,导致fetchTeams被触发了两次。

正确的调用位置应该是这样:

  1. 在每个异步请求发起前调用enter():也就是在forEach遍历每个标签时,刚拿到key就调用group.enter(),告诉DispatchGroup“我要开始一个新的异步任务了”。
  2. 在异步请求的回调结束时调用leave():在Firebase回调里,把UID添加到数组的操作完成后,调用group.leave(),告诉DispatchGroup“这个任务完成了”。
  3. 在所有迭代之外设置notify:等所有enter的任务都leave后,notify里的闭包就会执行,这时候再调用fetchTeams,就能保证只执行一次,而且数组是完整的。

修正后的代码如下:

func filterTempo(filterTag: FilteredTags) {
    let group = DispatchGroup()
    let tag = filterTag.selectedTag.components(separatedBy: "/") // 返回"NewYork"和"baseball"
    // 先清空数组,避免之前的数据干扰
    self.arrays.removeAll()
    
    tag.forEach { (key) in
        // 每个标签对应一个异步任务,先标记任务开始
        group.enter()
        
        self.ref.child("tags").child(key).observe(.value, with: { (snapshot) in
            defer {
                // 用defer确保不管解析是否成功,都能标记任务完成,避免group卡死
                group.leave()
            }
            
            guard let dictionary = snapshot.value as? [String:Any] else { return }
            for (uid,_) in dictionary {
                self.arrays.append(uid)
            }
        }, withCancel: { _ in
            // 如果请求被取消,也要标记任务完成
            group.leave()
        })
    }
    
    // 所有异步任务完成后,在主队列执行fetchTeams
    group.notify(queue: .main) {
        // 可选:如果需要去重,可以转成Set再转回数组
        // let uniqueUids = Array(Set(self.arrays))
        // self.fetchTeams(array: uniqueUids)
        self.fetchTeams(array: self.arrays)
    }
}

另外提个小建议:你的数组里会出现重复的UID(比如uid1在两个标签里都存在),如果业务上需要唯一的UID列表,可以把数组转成Set再转回数组,这样传给fetchTeams的就是去重后的结果了。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 08:12:31