0

I wanted to add a delay to a swift 3 program and found good examples here at SO using DispatchQueue.main.asyncAfter(). I tested it in Playground and it it does add a delay. What baffles me though is that adding a delay of 61 (secs.) apparently spends 67 secs.

let date1: Date = Date.init()

func print_delay(s: String) -> Void {
    print(s)
}

func delay(d: Double) -> Void {
    DispatchQueue.main.asyncAfter(deadline: .now() + d) {
        let date2: Date = Date.init()
        let calendar: Calendar = Calendar.current
        let components: DateComponents = calendar.dateComponents([.year, .month, .day, .hour, .second], from: date1, to: date2)
        print_delay(s: "delta: \(components.second!)")
    }
}

let delay_array = [1.0, 5.9, 10.2, 22.1, 31.5, 40.9, 51.8, 61.0]

for item in delay_array {
    delay(d: item)
}

delta: 1
delta: 5
delta: 10
delta: 22
delta: 34
delta: 42
delta: 56
delta: 67

So I tested the same code in a command line program to see if it was more accurate but it also have the difference in the time. This is on macos sierra, latest xcode and on a macbook pro from 2012.

kometen
  • 6,536
  • 6
  • 41
  • 51

1 Answers1

1
let key = readLine()!

blocked the main thread until you do some input. .asyncAfter will dispatch your code in the same thread, but the code is not able to run until readLine finished.

UPDATE

try in the Playground

import PlaygroundSupport
PlaygroundPage.current.needsIndefiniteExecution = true

import Dispatch
import Foundation

let t = DispatchSource.makeTimerSource(flags: .strict, queue: DispatchQueue.main)
t.scheduleRepeating(deadline: .now(), interval: 3.0)
var i = 10
t.setEventHandler {
    print(Date())
    i -= 1
    if i < 0 {
        PlaygroundPage.current.finishExecution()
    }
}
t.resume()

something much closer to you needs :-)

import PlaygroundSupport
PlaygroundPage.current.needsIndefiniteExecution = true

import Dispatch
import Foundation

let delay_array = [1.0, 5.9, 10.2, 22.1, 31.5, 40.9, 51.8, 61.0]
var tarr:[DispatchSourceTimer] = []
let start = Date()
let dt: DispatchTime = .now()

for delay in delay_array {
    let t = DispatchSource.makeTimerSource(flags: .strict, queue: DispatchQueue.main)
    t.scheduleOneshot(deadline: dt + delay)
    t.setEventHandler {
        print(start.timeIntervalSinceNow)
    }
    t.resume()
    tarr.append(t)
}

There is not necessary to use an array of dispatch sources, you can reuse the source ... it is up to you. Look at the precision :-), it is great, isn't it?

reusing the same source, you can write something like

import PlaygroundSupport
PlaygroundPage.current.needsIndefiniteExecution = true

import Dispatch
import Foundation

let delay_array = [1.0, 5.9, 10.2, 22.1, 31.5, 40.9, 51.8, 61.0]
let start = Date()

let dt: DispatchTime = .now()
let t = DispatchSource.makeTimerSource(flags: .strict, queue: DispatchQueue.main)

var i = 0
t.scheduleOneshot(deadline: dt + delay_array[i])

t.setEventHandler {
    print(start.timeIntervalSinceNow)
    t.suspend()
    i += 1
    if i < delay_array.count {
        t.scheduleOneshot(deadline: dt + delay_array[i])
        t.resume()
    } else {
        t.cancel()
        PlaygroundPage.current.finishExecution()
    }
}
t.resume()
user3441734
  • 16,722
  • 2
  • 40
  • 59
  • @kometen as expected :-) – user3441734 May 30 '17 at 05:50
  • Off-course, you're right, my bad. :-) But why the difference in time? – kometen May 30 '17 at 08:00
  • I'll remove the last part of my question. It was the first part with the difference that was the actual question, but I phrased it bad. – kometen May 30 '17 at 08:14
  • As is clear from the name asyncAfter will be executed at any time after. Don't use it for anything where execution at precise time is required. Use Timer, or look at DispatchSource for something more precise – user3441734 May 30 '17 at 08:24
  • Thank you. I'll remove my question since there are already enough posts about asyncAfter() and you give an explanation to the difference in time. And my question does not bring something new to the topic. – kometen May 30 '17 at 08:34
  • Thank you, this is much more accurate. – kometen May 30 '17 at 19:32