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

Firestore异步setData方法无法抛出服务端错误该如何处理

问题原因

Firestore的setData(from:)有两个行为完全不同的重载:

  • 无回调版本:为乐观写入设计,调用后立即在本地缓存生效,不等待服务端响应,仅会抛出本地编码错误、无效引用等本地侧问题,不会返回服务端权限错误、网络错误等服务端响应的错误。
  • 带完成回调版本:会等待服务端返回写入结果,回调入参的可选error就是服务端/网络层返回的写入异常。

回调属于逃逸闭包,执行时外层函数的调用栈已经退出,直接在回调闭包内throw无法被外层async throws上下文捕获,必须通过Swift并发提供的续体(continuation)桥接才能把错误向外抛出。

实现代码

使用withCheckedThrowingContinuation将回调式API桥接到异步抛出上下文,修改后的方法实现如下:

import Foundation
import FirebaseFirestore

class DatabaseProvider: ObservableObject {
    
    static let shared = DatabaseProvider()
    private var db = Firestore.firestore()
    
    private init() {}
}

// MARK: 文档增删改查相关方法
extension DatabaseProvider {
    
    /// 通用数据写入方法
    /// - Parameters:
    ///   - collection: 数据要写入的集合
    ///   - documentId: 可选自定义文档ID,传nil时自动生成ID
    ///   - data: 要写入的可序列化数据对象
    func addDocument<T: Codable>(
        to collection: Collections,
        documentId: String? = nil,
        with data: T
    ) async throws {
        let collectionReference = db.collection(collection.name)
        let documentReference: DocumentReference
        if let documentId = documentId {
            documentReference = collectionReference.document(documentId)
        } else {
            documentReference = collectionReference.document()
        }
        
        // 桥接回调API到async/throws上下文,等待服务端响应后再返回/抛出错误
        try await withCheckedThrowingContinuation { continuation in
            documentReference.setData(from: data.self) { error in
                if let error = error {
                    continuation.resume(throwing: error)
                } else {
                    continuation.resume()
                }
            }
        }
    }
}

注意:实现时删除原来无回调的setData调用,否则会触发重复写入。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.28 21:48:19