How to use DispatchGroup to update UI only after for-in loop has completed

288 views Asked by At

When a user taps a button, that triggers a lengthy function consisting of an API call and calculations.

@IBAction func buttonTapped(_ sender: Any) {
        
        var itemIndex = 0
        let dispatchGroup = DispatchGroup()
        
        for name in (entireRecipe?.extendedIngredients!)! {
            
            dispatchGroup.enter()
            
            CalculatorService().calculate() { item   in
                self.arrayItem.append(item)
                self.totalItems = self.arrayItems.reduce(0, +)
            }
            itemIndex = itemIndex + 1
        }
        dispatchGroup.leave()
        
        dispatchGroup.notify(queue: .main) {
            print("DispatchGroup Notified")
            self.itemLabel.text = "\(self.totalItems)"
        }
    }

My rationale on the above is that:

  1. dispatchGroup is entered when the for-in loop starts
  2. dispatchGroup is left after the for-in loop has iterated through the entire array
  3. dispatchGroup is only then notified, and the UI label is updated

However, it looks like dispatchGroup.notify is not being run when intended, and so the UI label is not being updated after the for-in loop is complete.

Is there anything missing from my dispatchGroup code? Any help is much appreciated!

1

There are 1 answers

5
vadian On BEST ANSWER

The leave line must be inside the closure

for name in (entireRecipe?.extendedIngredients!)! {
    
    dispatchGroup.enter()
    
    CalculatorService().calculate() { item   in
        self.arrayItem.append(item)
        self.totalItems = self.arrayItems.reduce(0, +)
        dispatchGroup.leave()
    }
    itemIndex = itemIndex + 1
}