eugene_prg
eugene_prg

Reputation: 1168

Fetching data from Firebase - completion handler?

I need to fetch the data from Firebase database and my function is represented by two loops (one inside another). The code looks like this:

// THE 1ST LOOP FETCHING THE LIST OF EQUIPMENT
self.db.collection("fl_content")
            .whereField("_fl_meta_.schema", isEqualTo: "equipment")
            .whereField("active", isEqualTo: true)
            .getDocuments() {
                (querySnapshot, err) in

                if let err = err {
                    print("Error getting documents: \(err)");
                } else {
                    var imagesToFetch: [String : String] = [:]

                    for equipmentDocument in querySnapshot!.documents {
                        if
                            let name = equipmentDocument.data()["name"] as? String, let images = equipmentDocument.data()["image"] as? [DocumentReference], let active = equipmentDocument.data()["default"] as? Bool, let def = equipmentDocument.data()["default"] as? Bool {
                            var documentData: [String: Any] = [:]
                            documentData["name"] = name
                            documentData["active"] = active
                            documentData["default"] = def
                            documentData["image"] = images[0].documentID
                            equipmentData[equipmentDocument.documentID] = documentData
                            if images.indices.contains(0) {

                                if FileManager.fileExists(path: "\(Constants.fileSavePath)\(images[0].documentID)") {
                                    self.toolList.append(
                                        Equipment(
                                            fbid: equipmentDocument.documentID,
                                            name: name,
                                            image: (documentData["image"] != nil) ? FileManager.fileToUIImage(path: images[0].documentID) : nil,
                                            active: active,
                                            def: def)
                                    )
                                } else {
                                    imagesToFetch[equipmentDocument.documentID] = images[0].documentID
                                }
                            }

                        } else {
                            print("No 'name' or 'image' found for this journey")
                        }
                    }
                    // got all data, let's get file paths and check if files exist
                    if(!imagesToFetch.isEmpty) {
                        // fetching paths to the images
                        self.db.collection("fl_files").whereField("_fl_meta_.docId", in: Array(imagesToFetch.values)).getDocuments() { 
                            (querySnapshot, err) in
                            if let err = err {
                               print("Error getting documents: \(err)");
                            } else {
                               for imageDocument in querySnapshot!.documents {
                                 // Getting file paths from Firebase .....
                                 **HERE COMES THE 2ND LOOP FETCHING THE IMAGES FOR EACH GEAR**
                    }
                }
            }
        }
    }
}

The problem is I need to form an array and pass this array (when all requests are done and data is fetched) to the next View. But I don't know how to tell if ALL Firebase requests have been processed.

If I place my code after those 2 loop, it might be executed before all the data is fetched, right? Some requests might still be in progress

So how can I guaranteed that my array with the data is ready?

When this sort of data is used for UI updates I don't really care is all is done as UI is subscribed to my "published" variables, but in this case i wanna be able to detect when ALL REQUESTS are finished and data is fetched.

What's the best way of doing this? Should i use the counter to check that all requests are completed and use completion handler?

Upvotes: 0

Views: 177

Answers (1)

Cuneyt
Cuneyt

Reputation: 981

You can use DispatchGroup. Use enter() and leave() functions to decide when a new task will start and did finish. Then, use notify() function to do whatever you need to do when the dispatch group is empty (which is decided by counting enter and leave actions).

Upvotes: 1

Related Questions