简体   繁体   English

在使用 Swift 的 iOS 应用程序中使用 DispatchQueue 等待数据从 Cloud Firestore 返回时遇到问题

[英]Having trouble using DispatchQueue to wait for data to return from Cloud Firestore in iOS app using Swift

I'm trying to use DispatchQueue to get my code to wait until a query retrieves the results I need from Cloud Firestore before it continues executing, but just haven't been able to get it to work.我正在尝试使用 DispatchQueue 让我的代码等待查询从 Cloud Firestore 检索到我需要的结果,然后再继续执行,但一直无法让它工作。 In the code below I am trying to get it to wait until the data has been retrieved and stored in the zoneMarkerArray, and then print out the result.在下面的代码中,我试图让它等到数据被检索并存储在 zoneMarkerArray 中,然后打印出结果。

I've numbered each line it prints in the order that I want it to happen, and as you'll see in the output it is not waiting for the Firestore result before moving on.我已经按照我希望它发生的顺序对它打印的每一行进行了编号,并且正如您在输出中看到的那样,它不会在继续之前等待 Firestore 结果。

Here is my code:这是我的代码:

let zones = self.db.collection("zones")

let zonesQuery = zones.whereField("start", isGreaterThan: lowerLimit).whereField("start", isLessThan: upperLimit)

print("1. zones Query has been defined")

//pass zonesQuery query to getZoneMarkers function to retrieve the zone markers from Firestore      
getZoneMarkers(zonesQuery)

print("6. Now returned from getZoneMarkers")


func getZoneMarkers(_ zonesQuery: Query) -> ([Double]) {
    print("2. Entered getZoneMarkers function")
    DispatchQueue.global(qos: .userInteractive).async {         

        zonesQuery.getDocuments() { (snapshot, error) in

            if let error = error {
            print("Error getting zone markers: \(error)")
            } else {

                print("3. Successfully Retrieved the zone markers")
            var result: Double = 0.0

                for document in snapshot!.documents {

                    print("Retrieved zone marker is \(document["start"]!)")
                    self.zoneMarkerArray.append(document["start"]! as! Double)
                    print("4. Looping over zone marker results")

                }
            }
        }

        DispatchQueue.main.async { 
      //I want this the printCompleted function to print the result AFTER the results have been retrieved  
            self.printCompleted()

        }
    }   

    return self.zoneMarkerArray

}


func printCompleted() {
    print("5. Looping now completed. Result was \(zoneMarkerArray)")
}

And here is the output that prints out:这是打印出来的输出:

  1. zones Query has been defined区域查询已定义
  2. Entered getZoneMarkers function进入 getZoneMarkers 函数
  3. Now returned from getZoneMarkers现在从 getZoneMarkers 返回
  4. Looping now completed.循环现在完成。 Result was [0.0]结果是 [0.0]
  5. Successfully Retrieved the zone markers成功检索区域标记
  6. Looping over zone marker results循环区域标记结果
  7. Looping over zone marker results Retrieved zone marker is 12.0循环区域标记结果检索到的区域标记为 12.0
  8. Looping over zone marker results循环区域标记结果

Thanks for the help!谢谢您的帮助!

EDIT: In case anyone else out there is also struggling with this, here's the working code I put together in the end based on the feedback I received.编辑:如果其他人也在为此苦苦挣扎,这是我根据收到的反馈最终汇总的工作代码。 Please feel free to critique if you see how it could be further improved:如果您看到如何进一步改进,请随时提出批评:

let zones = self.db.collection("zones")

let zonesQuery = zones.whereField("start", isGreaterThan: lowerLimit).whereField("start", isLessThan: upperLimit)


print("1. zones Query has been defined")

//pass zonesQuery query to getZoneMarkers function to retrieve the zone markers from Firestore      
getZoneMarkers(zonesQuery)

func getZoneMarkers(_ zonesQuery: (Query)) {
    print("2. Entered getZoneMarkers function")
  zoneMarkerArray.removeAll()

    zonesQuery.getDocuments(completion: { (snapshot, error) in
        if let error = error {
            print("Error getting zone markers: \(error)")
            return
        }

        guard let docs = snapshot?.documents else { return }

        print("3. Successfully Retrieved the zone markers")


        for document in docs {

            self.zoneMarkerArray.append(document["start"]! as! Double)
            print("4. Looping over zone marker results")

        }

        self.completion(zoneMarkerArray: self.zoneMarkerArray)

    })
}


func completion(zoneMarkerArray: [Double]) {
    print("5. Looping now completed. Result was \(zoneMarkerArray)")   

}

Maybe this can help you.也许这可以帮助你。 I have a lot of users, it appends to my Model, and can check when I have all the data und go on with my code:我有很多用户,它附加到我的模型,并且可以检查我何时拥有所有数据并继续使用我的代码:

func allUser (completion: @escaping ([UserModel]) -> Void) {

let dispatchGroup = DispatchGroup()
var model = [UserModel]()

let db = Firestore.firestore()
let docRef = db.collection("users")
dispatchGroup.enter()
docRef.getDocuments { (querySnapshot, err) in

    for document in querySnapshot!.documents {
        print("disp enter")
        let dic = document.data()
        model.append(UserModel(dictionary: dic))
    }
     dispatchGroup.leave()
}
dispatchGroup.notify(queue: .main) {
    completion(model)
    print("completion")
}

} }

From the question, it doesn't appear like any DispatchQueue's are needed.从问题来看,似乎不需要任何 DispatchQueue。 Firestore asynchronous so data is only valid inside the closures following the firebase function. Firestore 是异步的,因此数据仅在 firebase 函数之后的闭包内有效。 Also, UI calls are handled on the main thread whereas networking is on the background thread.此外,UI 调用在主线程上处理,而网络在后台线程上处理。

If you want to wait for all of the data to be loaded from Firestore, that would be done within the closure following the Firestore call.如果您想等待从 Firestore 加载所有数据,这将在 Firestore 调用之后的闭包内完成。 For example, suppose we have a zones collection with documents that store start and stop indicators例如,假设我们有一个区域集合,其中包含存储开始和停止指示符的文档

zones
   zone_0
      start: 1
      stop:  3
   zone_1
      start: 7
      stop:  9

For this example, we'll be storing the start and stop for each zone in a class array of tuples对于这个例子,我们将在一个元组类数组中存储每个区域的开始和停止

var tupleArray = [(Int, Int)]()

and the code to read in the zones, populate the tupleArray and then do the 'next step' - printing them in this case.以及在区域中读取的代码,填充 tupleArray 然后执行“下一步” - 在这种情况下打印它们。

func readZoneMarkers() {
    let zonesQuery = self.db.collection("zones")
    zonesQuery.getDocuments(completion: { documentSnapshot, error in
        if let err = error {
            print(err.localizedDescription)
            return
        }

        guard let docs = documentSnapshot?.documents else { return }

        for doc in docs {
            let start = doc.get("start") as? Int ?? 0
            let end = doc.get("end") as? Int ?? 0
            let t = (start, end)
            self.tupleArray.append(t)
        }

        //reload your tableView or collectionView here,
        //    or proceed to whatever the next step is
        self.tupleArray.forEach { print( $0.0, $0.1) }
    })
}

and the output和输出

1 3
7 9

Because of the asynchronous nature of Firebase, you can't 'return' from a closure, but you can leverage a completion handler if needed to pass the data 'back' from the closure.由于 Firebase 的异步特性,您不能从闭包“返回”,但如果需要,您可以利用完成处理程序将数据从闭包“返回”。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 在ios swift中使用云端防火墙进行电话身份验证? - Phone authentication using cloud firestore in ios swift? 使用 Swift 更新 Cloud Firestore 数据库中的数据 - Update data in Cloud Firestore database using Swift 在 iOS 中使用 Firebase/Firestore 填充 tableView 时遇到问题 - Having trouble populating tableView using Firebase/Firestore in iOS iOS Swift 5 在 TabBarController 的视图控制器中使用来自云数据库的数据 - iOS Swift 5 Using Data from Cloud Database in View Controllers in TabBarController 在Swift 4中异步使用dispatchQueue加速 - dispatchqueue using in asynchronously to speedup in Swift 4 在 swift 3 中使用 NotificationCenter 停止 Dispatchqueue - Stop Dispatchqueue using NotificationCenter in swift 3 如何使用 Xcode 中的 Swift 访问 Firebase 中的 Cloud Firestore 数据库中的数据? - How do I access the data from Cloud Firestore database in Firebase using Swift in Xcode? 在iOS Swift中使用Delegated和Protocols从dataTaskWithRequest返回数据 - Using Delegated and Protocols to return data from dataTaskWithRequest in iOS Swift iOS应用程序没有使用笔尖,无法启动 - iOS app using no nibs, having trouble getting off the ground 图请求 Facebook iOS swift 不工作我试图获取用户数据并将其上传到应用程序 Cloud Firestore - Graph request Facebook iOS swift not working Im trying to take the user data and upload it into app Cloud Firestore
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM