As others have pointed out, which thread the code runs on really doesn't matter. Performance issues like this are typically dependent on simply running the tasks sequentially, one at a time, so they don't overlap or collide with resources.
The simplest solution is to create a sequential queue. (typed in Safari, so worth every penny you paid for it)
let queue = DispatchQueue(label: "db.update", qos: .utility, attributes: [], autoreleaseFrequency: .inherit, target: nil)
var progress: Int = 0
queue.async {
// Dome some work, then update the UI
progress = 2
DispatchQueue.main.async(execute: {
// label.text = "did something"
// progress.doubleValue = Double(progressCounter)
})
}
queue.async {
// Do some more work
progress += 1
// This won't execute until the first block has finished
}
queue.async {
// Even more work
progress += 1
}
queue.async {
// And so on...
progress += 1 // This block might, for example, notify the system that everything has finished
print("progress is finally \(progress)")
}
The key is that each block executes sequentially (because the queue is not "concurrent"), and the next block won't start until the previous one has finished. Each block may, or may not, execute on the same thread, but it should't matter.
The results/progress of one block can easily be passed to the next block via closure variables.