I am trying to process over an array of simple elements, where on every element of the array a time-consuming process of updating the UI with a Timer will be started. The order of the elements in the array is important and matters. For simplicity sake I simplified the code down to this:
func processArray() {
let signals = [0, 1, 0, 1, 1]
for element in signals {
//pause and process first element
timeConsumingProcess(e: element)
//after processing first element finished, continue to next element
}
}
func timeConsumingProcess(e: Int) {
Timer.scheduledTimer(withTimeInterval: 2, repeats: false) { timer in
// 2 seconds set for demonstration purposes, can take more or less depending on the element
// doing something with e in UI
timer.invalidate()
}
}
How can I pause array iteration while the time consuming timeConsumingProcess(e: Int)
is happening?
I tried using OperationQueues, DispatchGroups, DispatchSerialQueues, sync{}
blocks, but to no avail. I'm guessing with the advancement of Swift concurrency and Async/Await
there should be an elegant and efficient solution to it, but I just can't wrap my head around it. Sequentially processing time-consuming events has never been easy in Swift, but I'm entirely at a loss here, so any help would be greatly appreciated!
You can use async-await to achieve this. Something like this should work. Where the print
is the place to make your UI changes. (you'll need to DispatchQueue.main.async any UI Changes)
let array = [0,1,2,3,4,5]
Task {
for item in array {
await doAThing(item)
}
}
func doAThing(_ item: Int) async {
print("\(item)")
try? await Task.sleep(nanoseconds: UInt64(2 * Double(NSEC_PER_SEC)))
}
If you can't use async await due to lower api support, you can use DispatchQueue.asyncAfter like so:
DispatchQueue.main.asyncAfter(deadline: .now() + (2 * arrayIndex)) {
// Put your code which should be executed with a delay here
}
With this you won't use a for loop but instead you'll need a DispatchQueue.asyncAfter for each item in your array and it'll handle it's own logic.