SwiftUI视图加载前无法获取Firestore数据 异步处理逻辑问题
问题根源
问题核心是两个异步请求并行执行,回调返回顺序不可控,等值校验仅在getRoom回调中触发,若getRoom回调早于getNumParticipants返回,此时numParticipants还停留在初始值0,无法正确匹配已返回的totalAnswered,且后续numParticipants赋值完成后没有再次触发校验逻辑,导致首次加载时哪怕两个值实际相等也不会设置showResults = true。另外isLoading = false的位置错误,异步请求还未执行完成就会被提前设为false。
修复方案
1. 抽离公共校验方法
在ViewModel中新增单独的等值校验方法,两个异步请求赋值完成后都调用该方法,确保不管哪个请求先返回,只要两个值都更新完成就能触发校验。
2. 调整异步逻辑与状态位位置
修改checkShowResults方法,确保isLoading仅在两个请求都完成后才修改。
修改后的ViewModel完整代码如下:
// 原有三个变量保持不变 @Published var numParticipants = 0 @Published var totalAnswered = 0 @Published var showResults = false @Published var isLoading = false // 新增:抽离的公共校验方法 private func checkIfShouldShowResults() { DispatchQueue.main.async { if self.totalAnswered == self.numParticipants { self.showResults = true } // 两个值都脱离初始值说明异步请求已全部返回 if self.totalAnswered != 0 || self.numParticipants != 0 { self.isLoading = false } } } // 原有getRoom、getNumParticipants方法无需修改 // 修改后的校验触发方法 func checkShowResults(roomId: String) { isLoading = true // 重置状态避免旧数据干扰 numParticipants = 0 totalAnswered = 0 showResults = false self.getNumParticipants(roomId: roomId) { [weak self] numParticipants in guard let self = self else { return } print("Number of docs: \(numParticipants)") self.numParticipants = numParticipants // 赋值后触发校验 self.checkIfShouldShowResults() } self.getRoom(roomId: roomId) { [weak self] room in guard let self = self else { return } print("Total answered: \(room.totalAnswered)") self.totalAnswered = room.totalAnswered // 赋值后触发校验 self.checkIfShouldShowResults() } }
可选优化
如果业务中参与人数会动态增加,可将getNumParticipants中的getDocuments也替换为addSnapshotListener,和房间数据的监听器保持一致,后续参与人数变动时也能自动触发校验。
内容的提问来源于stack exchange,提问作者Liam
相关产品推荐
相关产品推荐

