Search code examples
swiftxcodegrand-central-dispatch

GCD - asyncAfter: How to run it synchronously


I have just started reading swift and i'm currently confused of how to use threading correctly.

What i'm trying to achieve in the following block of code, is to execute the print statements inside the dispatchers, but i want to do it in order. The problem that i have, is that of course i want to do this in a background thread than the main since this is a long task, and at the same time to execute it in order while i'm giving delay in the execution. The current block executes each of the cases all together.

I have also took a look in Timer and Semaphores but without any results.

Any help or explanation of what i'm doing wrong or what should i approach will be appreciated.

let formattedSeries = ["a", "a", "b"]
let dispatchQueue = DispatchQueue(label: "taskQueue")
let a = 1000
let b = 5000
for (index, letter) in (formattedSeries.enumerated()){

    switch letter {
    case "a":
        dispatchQueue.asyncAfter(deadline: .now() + .milliseconds(a), execute: {
            print("a executed")           
        })      
        break
    case "b":
        dispatchQueue.asyncAfter(deadline: .now() + .milliseconds(b), execute: {
            print("b executed")
        })
        break
    default:
        print("default")
    }
}

Solution

  • You can use a dispatch group to force the evaluation of the next letter to wait for evaluation of the previous letter:

    let dispatchGroup = DispatchGroup()
    let dispatchQueue = DispatchQueue(label: "taskQueue")
    let a = 1000
    let b = 5000
    let formattedSeries = "abbaabba"
    print("start", Date().timeIntervalSince1970)
    for (index, letter) in (formattedSeries.enumerated()){
        dispatchGroup.enter()
        switch letter {
        case "a":
            dispatchQueue.asyncAfter(deadline: .now() + .milliseconds(a), execute: {
                print("a executed", Date().timeIntervalSince1970)
                dispatchGroup.leave()
            })
            break
        case "b":
            dispatchQueue.asyncAfter(deadline: .now() + .milliseconds(b), execute: {
                print("b executed", Date().timeIntervalSince1970)
                dispatchGroup.leave()
            })
            break
        default:
            print("default")
        }
        dispatchGroup.wait()
    }
    

    I've added some extra output to prove that the intervals are correct. The output is

    start 1580060250.3307471
    a executed 1580060251.389974
    b executed 1580060256.889923
    b executed 1580060262.2758632
    a executed 1580060263.372933
    a executed 1580060264.373787
    b executed 1580060269.37443
    b executed 1580060274.375314
    a executed 1580060275.4726748
    

    which proves that we evaluated the letters in order, and that the async_after intervals elapse between the prints.