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

Posted

技术标签:

【中文标题】在 Playground 中的 swift 3 中添加延迟似乎不准确【英文标题】:Adding delay in swift 3 in Playground appears inaccurate 【发布时间】:2017-05-29 19:15:51 【问题描述】:

我想为 swift 3 程序添加延迟,并使用 DispatchQueue.main.asyncAfter() 在 SO 找到 good examples。我在 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 上。

【问题讨论】:

【参考方案1】:
let key = readLine()!

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

更新

去游乐场试试

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

【讨论】:

@kometen 符合预期:-) 偏离路线,你是对的,我的错。 :-) 但是为什么会有时间上的差异呢? 我将删除我问题的最后一部分。这是第一部分与实际问题的不同之处,但我措辞不好。 从名称中可以清楚地看出 asyncAfter 将在之后的任何时间执行。不要将它用于需要在精确时间执行的任何事情。使用 Timer,或者查看 DispatchSource 以获得更精确的信息 谢谢。我将删除我的问题,因为关于 asyncAfter() 的帖子已经足够多,并且您对时间差异进行了解释。我的问题并没有给这个话题带来新的东西。

以上是关于在 Playground 中的 swift 3 中添加延迟似乎不准确的主要内容,如果未能解决你的问题,请参考以下文章

在 Playground 的“SupportCode.swift”中导入第 3 方框架

无法让我在 Swift 中的计时器在 Playground 中触发

Swift 中的 Playground 不会使用 Firebase

Swift Playground 中的 CABasicAnimation

将图像添加到 swift Playground [iPad]

Swift 3 Playground 以本地格式记录日期。如何?