【发布时间】:2021-12-31 17:12:40
【问题描述】:
在加载视图之前检索 Firestore getdocument 数据时遇到问题。我知道它会从多个检查中返回值,并且我处理异步函数的方式可能存在问题。
我正在尝试设置的三个变量。
@Published var numParticipants = 0
@Published var totalAnswered = 0
@Published var showResults = false
这是第一个获取和设置参与者数量变量的函数。
func getRoom(roomId: String, onSuccess: @escaping(_ room: Room) -> Void) {
DB.collection("Rooms").document(roomId).addSnapshotListener { document, error in
DispatchQueue.main.async {
if let dict = document?.data() {
guard let decodeRoom = try? Room.init(fromDictionary: dict) else { return }
onSuccess(decodeRoom)
}
}
}
}
这是获取和设置总回答变量的第二个函数
func getNumParticipants(roomId: String, onSuccess: @escaping(_ numParticipants: Int) -> Void) {
DB.collection("RoomsParticipants").document(roomId).collection("Participants").getDocuments { snapshot, error in
DispatchQueue.main.async {
if let error = error {
print(error.localizedDescription)
return
} else {
onSuccess(snapshot!.count)
}
}
}
}
然后我使用最后一个函数来比较两个变量,如果它们相等则加载视图,否则就等到它们相等。
func checkShowResults(roomId: String) {
isLoading = true
self.getNumParticipants(roomId: roomId) { numParticipants in
print("Number of docs: \(numParticipants)")
DispatchQueue.main.async {
self.numParticipants = numParticipants
}
}
self.getRoom(roomId: roomId) { room in
print("Total answered: \(room.totalAnswered)")
DispatchQueue.main.async {
self.totalAnswered = room.totalAnswered
if self.totalAnswered == self.numParticipants {
self.showResults = true
}
}
}
isLoading = false
}
这是我尝试根据获取的数据显示的结果视图。
struct ResultsView: View {
@StateObject var resultsViewModel = ResultsViewModel()
var roomId: String
var body: some View {
VStack {
if !resultsViewModel.showResults {
VStack {
ProgressView()
Text("Waiting for all participants \nto finish answering...")
}
} else {
ShowResultsView()
}
}
}
}.navigationBarHidden(true)
.onAppear {
resultsViewModel.checkShowResults(roomId: roomId)
}
}
即使在最初显示视图时 totalAnswered 和 numParticipants 相等,showResults 也始终设置为 false。但是当数据发生变化时,如果它们再次相等,它最终会被设置为 true。我认为这是因为对 firebase/firestore 的 API 调用需要时间,并且在视图加载之前未设置变量。我真的不想使用 async/await。
【问题讨论】:
-
当前您的代码执行
self.getNumParticipants(..)独立于self.getRoom(roomId: roomId)。但是在checkShowResults中,self.getRoom(roomId: roomId)取决于您从self.getNumParticipants(..)获得的self.numParticipants。所以你可以尝试嵌套你的函数调用。也就是说,在设置了self.numParticipants之后,将self.getRoom(roomId: roomId)放在self.getNumParticipants(roomId: roomId)中。此外,我会将isLoading = false放在self.showResults = true之后的self.getRoom(roomId: roomId)中。 -
谢谢@workingdog 工作得很好。
-
好,我已经用这种方法发布了答案。
标签: xcode asynchronous google-cloud-firestore swiftui async-await