我试着用斯威夫特和GCD做一个很好的计时器。我在马特·纽伯格的书中发现了很多博客甚至是一个条目。我用后者把我自己的变体放在操场上:

import Foundation
struct Timer {
    private var queue = dispatch_queue_create("timer", nil)
    private var source: dispatch_source_t
    var tick:()->() = {} {
        didSet {
            self.update()
        }
    }
    var rate:Double = 1.0 {
        didSet {
            self.update()
        }
    }

    init() {
        self.source = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, self.queue)
        self.update()
    }

    func cancel() {
        dispatch_source_cancel(self.source)
    }

    func update() {
        dispatch_source_set_timer(self.source, DISPATCH_TIME_NOW, UInt64(Double(NSEC_PER_SEC) / self.rate), 0)
        dispatch_source_set_event_handler(self.source, self.tick)
    }

    func resume() {
        dispatch_resume(self.source)
    }
}

var timer = Timer()
timer.tick = {
    let now = NSDate()
    print("\(now)")
}
timer.cancel()
timer.resume()

我没有编译错误。但操场底部的控制台什么也没显示。如果我加上
timer.tick()

它输出当前日期的结果,显然只执行一次tick函数。我在马特的书中非常仔细地学习了他的例子(为了教育目的做了一些小的改变)。所以我不知道
a)它很好,当我把它移到真正的代码时,它会工作得很好,只是在操场输出中没有任何明显的显示
b)一些东西没有丢失,也没有真正开火

最佳答案

一旦源被dispatch_source_cancel取消,它将不再调用其事件处理程序。取消后,不能用dispatch_resume重新启用源;必须创建新的源。
要使您的游乐场正常工作,您必须取消对timer.cancel()的呼叫。
此外,在执行了整个游乐场脚本之后,游戏场进程默认退出。如果希望它继续运行,则需要设置XCPlaygroundPage.currentPage.needsIndefiniteExecution = true
所以让你的剧本结尾看起来像这样:

var timer = Timer()
timer.tick = {
    let now = NSDate()
    print("\(now)")
}
timer.resume()
XCPlaygroundPage.currentPage.needsIndefiniteExecution = true

10-08 05:45