swiftfor-loopdispatchgroup

How to use Dispatch Group in a loop with asynchronous Function Swift?


I have checked all the questions regarding this topic but none of them helped. I have a code like below. Now as soon as the code enters the for id in stringArray loop, it gets executed for the stringArray.count times without even entering the firestore asynchronous part. That's understandable, but not my requirement. I want myGroup.notify to be executed after the loop and the asynchronous code has finished. But as loop finishes readily and so myGroup.notify gets called even when asynchronous is yet to be finished. So, basically may be I am asking here to place the myGroup.enter and myGroup.leave at correct places. Thanks!

MyCode:

func Promise_searchedDataFromDB(stringArray:[String]) {
    for id in stringArray {
        myGroup.enter()
    collectionRef.getDocuments { (querySnapshot, error) in
        if error != nil {
            return
        }
        else {
               guard let snapshot = querySnapshot else {return}
               for document in snapshot.documents {
                
                let myData = document.data()
                if StaticVariable == true {
             
                    self.typeOfListing = myData["Type"] as? String ?? "Not Found"
                    self.charges = Int(myData["Charges"] as? String ?? "Not Found") ?? 0
                    self.nameOfListing = myData["Title"] as? String ?? "Not Found"
                    self.currency = myData["Currency"] as? String ?? "Not Found"
                    self.days = myData["Days"] as? String ?? "Not Found"
                    self.details = myData["Description"] as? String ?? "Not Found"
                    self.cityName = myData["City"] as? String ?? "Ghost"
                    
                    let dataArray = CellComponents(image: UIImage(named: "b")!, typeOfListing: self.typeOfListing , charges: self.charges, rating: 4.1, nameOfListing: self.nameOfListing , cityName: self.cityName, detail: self.details, currency: self.currency, days: self.days)
                    self.ArrayToHoldSearchedListing.append(dataArray)
                    self.tableView.reloadData()
                }
              }
            }
          }

             myGroup.leave()
       }
        
        myGroup.notify(queue: .main) {
            print("All done")
        }
   }

Solution

  • Leave within the async block not outside of it ... and enter should be equal to leave so put it in defer statement to always execute before leaving the scope

      func Promise_searchedDataFromDB(stringArray:[String]) {
         for id in stringArray {
             myGroup.enter()
         collectionRef.getDocuments { (querySnapshot, error) in
            defer{  myGroup.leave() }
            
             if error != nil {
                 return
             }
             else {
                    guard let snapshot = querySnapshot else {return}
                    for document in snapshot.documents {
                     
                     let myData = document.data()
                     if StaticVariable == true {
                  
                         self.typeOfListing = myData["Type"] as? String ?? "Not Found"
                         self.charges = Int(myData["Charges"] as? String ?? "Not Found") ?? 0
                         self.nameOfListing = myData["Title"] as? String ?? "Not Found"
                         self.currency = myData["Currency"] as? String ?? "Not Found"
                         self.days = myData["Days"] as? String ?? "Not Found"
                         self.details = myData["Description"] as? String ?? "Not Found"
                         self.cityName = myData["City"] as? String ?? "Ghost"
                         
                         let dataArray = CellComponents(image: UIImage(named: "b")!, typeOfListing: self.typeOfListing , charges: self.charges, rating: 4.1, nameOfListing: self.nameOfListing , cityName: self.cityName, detail: self.details, currency: self.currency, days: self.days)
                         self.ArrayToHoldSearchedListing.append(dataArray)
                         self.tableView.reloadData()
                     }
                   }
                 }
               }
    
                
            }
             
             myGroup.notify(queue: .main) {
                 print("All done")
             }
        }