Can't get my Timer in Swift to fire in Playground

匆匆过客 提交于 2019-12-11 11:58:17

问题


I'm trying to make a nice timer using Swift and GCD. I find lots of blogs and even an entry in Matt Neuburg's book. I used the latter to put together my own variant in a playground:

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

I have no compilation errors. But the console at the bottom of the playground shows nothing. If I add

timer.tick()

It outputs the result of the current date, apparently executing tick function once. I followed Matt's example in his book pretty closely (making small changes for education purposes). So I'm left with not knowing if

A) It's just fine and will work fine when I move it to real code, it just doesn't show anywhere apparent in the Playground output B) Somethings not missing and it's not really firing


回答1:


Once a source has been cancelled by dispatch_source_cancel, it will never call its event handler again. You cannot reenable the source with dispatch_resume after cancelling it; you must create a new source.

To make your playground work, you must remove the call to timer.cancel().

Furthermore, after the entire playground script has been executed, the playground process exits by default. If you want it to keep running, you need to set XCPlaygroundPage.currentPage.needsIndefiniteExecution = true.

So make the end of your script look like this:

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


来源:https://stackoverflow.com/questions/33379433/cant-get-my-timer-in-swift-to-fire-in-playground

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!