Swift’s DispatchGroups are useful for doing stuff after a group of asynchronous operations. In my Day Planner app, I’ve got to load items from the iOS calendars (where some of the APIs return asynchronously). Using a DispatchGroup allows me to efficiently wait for all the data to reload and then update the user interface to reflect the changes.

let dispatchGroup = DispatchGroup()

for item in self.items {
  
  // Signal that we're entering a new execution block
  dispatchGroup.enter()
  
  item.loadAsync {
    // Signal that we've finished.
    dispatchGroup.leave()
  }
}

dispatchGroup.notify(queue: .main, execute: {
  // Do something with the data, once all of the loadAsync calls have finished.
  self.tableView.reloadData()
})