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

SwiftUI中如何等待Firestore getDocuments()完成后再执行后续逻辑

解决Firestore异步调用等待问题的几种方案

我完全懂你踩的这个坑——Firestore的getDocuments是异步执行的,你的同步函数根本等不及它拉完数据就返回了空数组,这确实是新手处理异步逻辑时最容易犯的错误。下面给你几种实用的解决方案,从兼容旧版本的传统写法到现代异步语法都有,你可以根据项目的iOS版本选择:

方案1:使用闭包回调(兼容所有iOS版本)

首先修改你的getPledgesInProgress方法,不要直接返回数组,而是通过一个闭包来传递异步执行的结果:

func getPledgesInProgress(pledgePicked: Pledge, completion: @escaping ([Pledge]) -> Void) {
    let db = Firestore.firestore()
    var pledgesToReturn = [Pledge]()
    
    db.collection("Pledges")
        .getDocuments { (snapshot, error) in
            guard let snapshot = snapshot, error == nil else {
                // 错误处理:如果请求失败,返回空数组或你需要的默认值
                completion([])
                return
            }
            snapshot.documents.forEach({ (documentSnapshot) in
                let documentData = documentSnapshot.data()
                // 替换强制解包为可选绑定,避免崩溃
                if let id = documentData["ID"] as? Int {
                    pledgesToReturn.append(findPledgeWithThisID(ID: id))
                }
            })
            // 异步操作完成后,通过闭包把结果传出去
            completion(pledgesToReturn)
        }
}

然后修改initVars函数,调用这个方法并在闭包里更新你的@State变量(SwiftUI更新状态要确保在主队列,Firestore的回调默认已经在主队列,但加上DispatchQueue.main.async更稳妥):

func initVars(){
    getPledgesInProgress(pledgePicked: pledgePicked ?? emptyPledge) { [weak self] pledges in
        DispatchQueue.main.async {
            self?.pledgesInProgress = pledges
        }
    }
}

方案2:使用Async/Await(iOS 15+ / macOS 12+)

如果你的项目已经适配了iOS 15及以上,用Swift原生的异步语法会更简洁直观。先把getPledgesInProgress改成异步函数:

func getPledgesInProgress(pledgePicked: Pledge) async throws -> [Pledge] {
    let db = Firestore.firestore()
    // 用try await替代闭包,直接获取异步结果
    let snapshot = try await db.collection("Pledges").getDocuments()
    
    var pledgesToReturn = [Pledge]()
    snapshot.documents.forEach({ (documentSnapshot) in
        let documentData = documentSnapshot.data()
        if let id = documentData["ID"] as? Int {
            pledgesToReturn.append(findPledgeWithThisID(ID: id))
        }
    })
    return pledgesToReturn
}

然后在initVars里用Task来调用异步函数,更新状态:

func initVars(){
    Task {
        do {
            let pledges = try await getPledgesInProgress(pledgePicked: pledgePicked ?? emptyPledge)
            DispatchQueue.main.async {
                self.pledgesInProgress = pledges
            }
        } catch {
            // 处理错误,比如打印日志或设置默认值
            print("获取数据失败:\(error)")
            DispatchQueue.main.async {
                self.pledgesInProgress = []
            }
        }
    }
}

额外小贴士

  • 我把代码里的as!改成了可选绑定,这是更安全的写法,避免因为数据类型不匹配导致崩溃;
  • 建议把initVars的调用放在视图的onAppear回调里,这样能保证视图出现后才开始加载数据:
    var body: some View {
        VStack{
            // 你的视图内容
        }
        .onAppear {
            initVars()
        }
    }
    

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.29 19:37:50