Search code examples
loopsswift3xcode8delaydelayed-execution

Why putting a DispatchQueue delay function inside another DispatchQueue has no effect in Swift


Expected Behavior:

For i = 0, print statement called after 0 second .

For i = 1, print statement called after 1.1 seconds

For i = 2, print statement called after 2.2 seconds

Actual Behavior:

Print statement called after 0, 1, 2, 3 seconds respectively i.e. inner delay function is ignored.

So why the discrepancy?

    for i in 0...3 {

        DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(i), execute: {  

            DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(i/10), execute: {
                print("function was called")
            })      
        })
    }

Solution

  • There are a number of ways you could do this. Here are 3:

    Use a timer to repeat a block every second

    var i = 0
    Timer.scheduledTimer(withTimeInterval: 1, repeats: true) { timer in
        i += 1
        print("hello \(i)")
        if i == 5 {
            timer.invalidate()
        }
    }
    

    Dispatch multiple async tasks

    for i in 1...5 {
        DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(i)) {
            print("hello \(i)")
        }
    }
    

    Note: This queues all of the tasks up front and could overflow a queue if there were a large number of them.

    Run loop in background with sleep and switch to foreground to print

    DispatchQueue.global().async {
        for i in 1...5 {
            sleep(1)
            DispatchQueue.main.async {
                print("hello \(i)")
            }
        }
    }
    

    Note: This will drift a little (not be 1 second apart) if the work in the loop takes a significant amount of time.