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

如何让getStudents等待addSnapshotListener内代码执行完毕再返回?

解决方案

方案1:改用单次数据获取(适合仅需一次加载的场景)

如果你的需求只是一次性获取学生数据,而非实时监听数据变化,直接替换addSnapshotListener为getDocuments,结合async/await(iOS 15+、Swift 5.5+)实现同步等待:

func getStudents() async {
    do {
        let querySnapshot = try await db.collection(StudentViewModel.studentCollection).getDocuments()
        var updatedStudentDocuments: [Student] = []
        for studentDocument in querySnapshot.documents {
            let student = Student(
                id: studentDocument.documentID,
                name: studentDocument.data()["name"] as? String ?? ""
            )
            updatedStudentDocuments.append(student)
        }
        DispatchQueue.main.async {
            self.students = updatedStudentDocuments
        }
    } catch {
        print("ERROR | Getting Student Documents in Firestore Service: \(error)")
    }
}

调用示例(需在异步上下文执行):

await getStudents()
// 此时self.students已完成更新

方案2:保留实时监听,等待首次回调完成

如果必须保留addSnapshotListener的实时监听能力,同时要等待首次回调完成后再继续执行,可使用DispatchGroup:

func getStudents(completion: @escaping () -> Void) {
    let group = DispatchGroup()
    group.enter()
    
    var listener: ListenerRegistration?
    listener = db.collection(StudentViewModel.studentCollection).addSnapshotListener { [weak self] (querySnapshot, error) in
        guard let self = self else {
            group.leave()
            return
        }
        
        guard error == nil else {
            print("ERROR | Getting Student Documents in Firestore Service: \(String(describing: error))")
            group.leave()
            return
        }
        
        guard let snapshot = querySnapshot else {
            print("No documents to fetch!")
            group.leave()
            return
        }
        
        var updatedStudentDocuments: [Student] = []
        for studentDocument in snapshot.documents {
            let student = Student(
                id: studentDocument.documentID,
                name: studentDocument.data()["name"] as? String ?? ""
            )
            updatedStudentDocuments.append(student)
        }
        
        DispatchQueue.main.async {
            self.students = updatedStudentDocuments
            group.leave()
            // 若不需要持续监听,可在此移除监听
            // listener?.remove()
        }
    }
    
    // 等待首次回调完成(注意:不要在主线程调用,避免UI卡死)
    group.wait()
    completion()
}

关键说明

  • addSnapshotListener的设计初衷是实时监听数据变化,会在数据更新时多次触发回调,若仅需单次加载数据,优先使用getDocuments更合理。
  • 异步操作尽量避免强制阻塞线程,推荐用async/await或completionHandler的方式处理,保证线程不被阻塞,尤其是主线程。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.18 02:10:18