在 Playground 的 swift 3 中添加延迟似乎不准确

Adding delay in swift 3 in Playground appears inaccurate

我想为 swift 3 程序添加延迟,并在 SO 处使用 DispatchQueue.main.asyncAfter() 找到了 。我在 Playground 对其进行了测试,它确实增加了延迟。令我困惑的是,添加 61(秒)的延迟显然花费了 67 秒。

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

所以我在命令行程序中测试了相同的代码,看它是否更准确,但它在时间上也有差异。这是在 macos sierra 上,最新的 xcode 和 2012 年的 macbook pro 上。

let key = readLine()!

阻塞主线程直到你做一些输入。 .asyncAfter 将在同一线程中分派您的代码,但代码无法 运行 直到 readLine 完成。

更新

在 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()

更接近您需要的东西:-)

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)
}

没有必要使用调度源数组,你可以重用源...这取决于你。看看精度 :-),太棒了,不是吗?

重复使用同一个源,你可以这样写

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()