Business
Jobs
  • About Us
  • Solutions
    • Job Postings
      Post your job and receive qualified candidates in 48h.
    • Candidate Assessments
      500+ technical and psychological tests, plus anti-fraud.
    • Headhunting
      Tailor-made executive search from start to finish.
    • Payroll + EOR
      Payroll dispersal and EOR across 15+ LATAM countries.
  • Pricing
  • Jobs

0

317
Views
Swift- Waiting for asynchronous for-in loop to complete before calling completion handler swift

I'm baffled as to what is the best way to achieve this. I am trying to keep a running total of Double values that I am looping through and adding together, via a network call. Everything I've read says to use DispatchGroup. My completion either calls too early or doesn't get called at all and I've tried every configuration of .enter, .leave, and .wait that I can think of.

    let group = DispatchGroup()
    var runningTotal: Double = 0.00

    ref.observeSingleEvent(of: .value) { (snapshot) in
        guard let bills = snapshot.value as? [String: AnyObject] else {
            //error
            return
        }

        for billId in bills.keys {
            group.enter()
            print("Entering")
            Database.database().reference().child("bills").child(billId).observeSingleEvent(of: .value, with: { (snapshot) in
                guard let bill = snapshot.value as? [String: AnyObject] else {
                    return
                }
                if let amount = bill["amount"] as? Double {
                    runningTotal += amount
                }
                group.leave()
                print("Leaving")
            })
        }
        completion(runningTotal)
    }
    group.wait()
}
over 4 years ago · Santiago Trujillo
2 answers
Answer question

0

A couple of thoughts:

  1. Avoid ever calling wait from the main thread. The use cases for that are pretty limited. The notify is a much safer way to achieve the same thing.

  2. Make sure you call leave from every path inside you’re loop. This can be achieved nicely with defer block.

So:

func foo(completion: @escaping (Double?) -> Void) {
    ref.observeSingleEvent(of: .value) { snapshot in
        guard let bills = snapshot.value as? [String: AnyObject] else {
            //error
            completion(nil)
            return
        }

        let group = DispatchGroup()
        var runningTotal = 0.0

        for billId in bills.keys {
            group.enter()
            print("Entering")
            Database.database().reference().child("bills").child(billId).observeSingleEvent(of: .value) { snapshot in
                defer { group.leave() }
                guard let bill = snapshot.value as? [String: AnyObject] else {
                    return
                }
                if let amount = bill["amount"] as? Double {
                    runningTotal += amount
                }
                print("Leaving")
            }
        }
        group.notify(queue: .main) {
            completion(runningTotal)
        }
    }
}
over 4 years ago · Santiago Trujillo Report

0

You should wait until all group tasks are done, then call completion block.

Like below.

    var runningTotal: Double = 0.00

    ref.observeSingleEvent(of: .value) { (snapshot) in
        guard let bills = snapshot.value as? [String: AnyObject] else {
            //error
            return
        }

        let group = DispatchGroup()
        for billId in bills.keys {
            group.enter()
            print("Entering")
            Database.database().reference().child("bills").child(billId).observeSingleEvent(of: .value, with: { (snapshot) in
                guard let bill = snapshot.value as? [String: AnyObject] else {
                    group.leave()
                    return
                }
                if let amount = bill["amount"] as? Double {
                    runningTotal += amount
                }
                group.leave()
                print("Leaving")
            })
        }
        group.wait()
        completion(runningTotal)
    }
over 4 years ago · Santiago Trujillo Report
Answer question
Find remote jobs

Discover the new way to find a job!

Top jobs
Top job categories
Business
Post vacancy Pricing Sales
Legal
Terms and conditions Privacy policy
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Show me some job opportunities
There's an error!