如何在我的 for 循环之外执行代码(需要等到循环完成从 Firebase 数据库中检索数据)?

Posted

技术标签:

【中文标题】如何在我的 for 循环之外执行代码(需要等到循环完成从 Firebase 数据库中检索数据)?【英文标题】:How can I execute code outside of my for loop (which needs to wait until the loop has finished retrieving data from Firebase Database)? 【发布时间】:2020-09-16 23:10:45 【问题描述】:

我正在尝试显示一个按汽车旅行时间显示机构的表格视图。

    查询循环遍历数据库中的学校列表以检索其坐标 计算与用户当前位置的距离 如果距离小于 20 英里,请使用 MKDirections() 计算 eta 时间 计算出 eta 时间后,将相关信息附加到 table view 的数组中,按 eta 时间对数组进行排序,只保留前 10 个

这里的问题是,在用户当前位置 20 英里范围内通常有许多机构,并且 MKDirections() 限制了您可以在给定时间范围内计算 eta 时间的请求数量。所以,我的表格视图经常无法显示 eta 时间。

对我来说显而易见的解决方案是在计算 eta 时间之前对数组进行排序和修整(从而避免计算 eta 请求过多的问题)。

我尝试了什么:

    将 for 循环内的数据附加到“Array1” 排序和修剪 Array1 在 for 循环之外/之后,我遍历 Array1 以计算 eta 时间,然后将此数据附加到 Array2 中,Array2 将是为 tableview 提供数据的数组

我发现这不起作用,因为 for 循环之外/之后的代码在 for 循环完成之前执行。

            let schoolDB = Database.database().reference().child("Schools")
            schoolDB.observe(.value, with:  (snapshot) in
                self.subjectTimesArray.removeAll()
                for child in snapshot.children 
                    let schoolSnapshot = child as! DataSnapshot
                    let approvalString = schoolSnapshot.childSnapshot(forPath: "Approved").value as! String
                    if approvalString == "Yes" 
                        let schoolID = schoolSnapshot.key
                        let schoolName = schoolSnapshot.childSnapshot(forPath: "Name").value as! String
                        let schoolLatitude = schoolSnapshot.childSnapshot(forPath: "Latitude").value as! Double
                        let schoolLongitude = schoolSnapshot.childSnapshot(forPath: "Longitude").value as! Double
                        let schoolLocation = CLLocation(latitude: schoolLatitude, longitude: schoolLongitude)
                        let distance = schoolLocation.distance(from: self.userLocation) / 1600
                        
                        if distance < 20 
                            let subjectDB = Database.database().reference().child("Subject/" + schoolID + "/" + date)
                            subjectDB.observeSingleEvent(of: .value, with:  (subjectSnapshot) in
                                let startTime = subjectSnapshot.childSnapshot(forPath: "Maths/Start").value as! String
                                    
                                let userPlacemark = MKMapItem(placemark: MKPlacemark(coordinate: userLocation.coordinate))
                                let schoolPlacemark = MKMapItem(placemark: MKPlacemark(coordinate: schoolLocation.coordinate))
                                let directionsRequest = MKDirections.Request()
                                directionsRequest.source = userPlacemark
                                directionsRequest.destination = schoolPlacemark
                                directionsRequest.requestsAlternateRoutes = false
                                directionsRequest.transportType = .automobile
                                    
                                let directions = MKDirections(request: directionsRequest)
                                directions.calculateETA(completionHandler:  (response, error) in
                                    if let seconds = response?.expectedTravelTime 
                                        let minutes = seconds / 60    
                                        self.subjectTimesArray.append(.init(schoolID: schoolID, schoolName: schoolName, distance: distance, eta: Int(minutes), subjectStart: startTime))
                                    
                                    
                                    self.subjectTimesArray.sort(by: $0.eta < $1.eta)
                                    if self.subjectTimesArray.count > 10 
                                            self.subjectTimesArray.removeLast(self.subjectTimesArray.count - 10)
                                    
                                    self.subjectTimesTableView.reloadData()
                                )
                            )
                        
                    
                
            )

【问题讨论】:

【参考方案1】:

您可以创建一个函数,使用作为学校的参数计算距离,并在距离小于 20 英里时调用它,或者如果数据库中的每所学校在 20 英里以下,则将其附加到一个新数组中并计算大批。如果您执行第二个选项,它只会在 20 英里以下的学校循环,我会推荐第一个选项。

【讨论】:

以上是关于如何在我的 for 循环之外执行代码(需要等到循环完成从 Firebase 数据库中检索数据)?的主要内容,如果未能解决你的问题,请参考以下文章

Node.js 等到异步函数完成,然后继续执行其余代码

等到带有异步网络请求的 swift for 循环完成执行

如何等到承诺完成后再继续循环

等到 for 循环内的所有函数调用结束其执行 - Javascript

nodejs如何让for循环等到运行下一个循环实例

如何在DispatcherTimer结束之前暂停for循环?