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

Firestore异步查询未完成致后续代码报错问题求助

问题解决:Firestore查询未完成就执行后续代码导致数组越界

核心问题分析

你的代码存在两个关键问题:

  • Async/Await版本:你在getUser()里用的是闭包回调版的getDocuments(),没有使用Firestore提供的可await的异步API,导致async函数并没有真正等待查询完成就返回了。
  • Completion Handler版本:completion(true)被放在了for document循环内部,会在处理第一个文档时就触发回调,而非等所有文档处理完成后;如果集合为空,回调甚至不会被调用,后续代码永远得不到执行信号。

修正方案

方案1:正确使用Async/Await

Firestore从iOS 15+(配合Firebase SDK 8.10+)开始支持原生Async/Await,直接使用getDocuments()的异步版本即可:

// 修正后的getUser方法
func getUser() async throws {
    let querySnapshot = try await self.db.collection("userSetting").getDocuments()
    
    for document in querySnapshot.documents {
        // 用可选绑定避免强制解包崩溃
        guard let userTrust = document.data()["userTrust"] as? String,
              let userGrade = document.data()["userGrade"] as? String,
              let userDisclaimer = document.data()["userDisclaimer"] as? String else {
            print("文档字段缺失或类型错误")
            continue
        }
        
        let row = [userTrust, userGrade, userDisclaimer]
        self.userArray.append(row)
        
        self.userTrustInfo = userTrust
        self.userGradeInfo = userGrade
    }
}

调用方式(在didFinishLaunchingWithOptions中)

注意:didFinishLaunchingWithOptions必须立即返回true,所以需要在Task内部等待查询完成后,再执行依赖userArray的代码:

internal func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
    FirebaseApp.configure()
    db = Firestore.firestore()
    Database.database().isPersistenceEnabled = true

    Task {
        do {
            // 等待用户数据加载完成
            try await getUser()
            // 这里执行依赖userArray的代码,比如初始化UI、跳转页面等
            print("用户数据加载完成:\(userArray)")
            setupMainUI() // 示例:调用依赖数据的方法
        } catch {
            print("加载用户数据失败:\(error)")
            // 处理错误,比如显示错误页面
        }
    }
    
    return true
}

方案2:正确使用Completion Handler

把completion移到循环外部,确保所有文档处理完成后再触发回调;同时处理错误场景,避免回调丢失:

// 修正后的getUser方法
func getUser(completion: @escaping (Bool, Error?) -> Void) {
    self.db.collection("userSetting").getDocuments() { (querySnapshot, err) in
        if let err = err {
            print("Error getting documents: \(err)")
            completion(false, err)
            return
        }
        
        guard let documents = querySnapshot?.documents else {
            print("没有查询到文档")
            completion(true, nil)
            return
        }
        
        for document in documents {
            guard let userTrust = document.data()["userTrust"] as? String,
                  let userGrade = document.data()["userGrade"] as? String,
                  let userDisclaimer = document.data()["userDisclaimer"] as? String else {
                print("文档字段异常")
                continue
            }
            
            let row = [userTrust, userGrade, userDisclaimer]
            self.userArray.append(row)
            
            self.userTrustInfo = userTrust
            self.userGradeInfo = userGrade
        }
        
        // 所有文档处理完成后再调用回调
        completion(true, nil)
    }
}

调用方式

internal func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
    FirebaseApp.configure()
    db = Firestore.firestore()
    Database.database().isPersistenceEnabled = true

    getUser { [weak self] success, error in
        guard let self = self else { return }
        
        if success {
            // 执行依赖userArray的代码
            print("用户数据加载完成:\(self.userArray)")
            self.setupMainUI()
        } else {
            print("加载失败:\(error?.localizedDescription ?? "未知错误")")
            // 错误处理
        }
    }
    
    return true
}

额外建议

  • 避免使用as!强制解包,改用as?配合可选绑定,防止字段缺失或类型错误导致崩溃。
  • 如果userSetting集合只有一个用户文档,可以直接用document()获取单文档,而非查询整个集合,提升效率。
  • 若启动时必须等待数据加载完成才能进入主界面,可以添加启动屏(Launch Screen)或加载指示器,避免用户看到空白或异常界面。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.02 03:05:49