为什么`scheduledTimer`在块外部设置时会正常触发,但不在块内?

Kev*_*vin 17 ios swift swift3

以下代码片段在完成块外部调用时工作正常,但是当我在块内部设置它时,定时器永远不会被触发.我不明白为什么会有区别:

self.timer = Timer.scheduledTimer(timeInterval: 1,
                                  target: self,
                                  selector: #selector(self.foo),
                                  userInfo: nil,
                                  repeats: true)
Run Code Online (Sandbox Code Playgroud)

我最初在块外调用它时没有使用自引用,但是一旦进入内部,就需要它.但是我再次在块外测试完全相同的代码,它仍然可以工作.

该块是完成处理程序,在请求HealthKit相关信息的许可后调用.

Rob*_*Rob 54

问题是有问题的完成块可能没有在主线程上运行,因此没有运行循环.但是定时器需要在运行循环上进行调度,而主线程有一个,大多数后台线程都没有(除非你自己添加一个).

为了解决这个问题,在该完成处理程序中,将计时器的创建发送回主线程,它应该可以正常工作:

DispatchQueue.main.async {
    self.timer = Timer.scheduledTimer(timeInterval: 1.0, target: self, selector: #selector(handleTimer(_:)), userInfo: nil, repeats: true)
}
Run Code Online (Sandbox Code Playgroud)

或者使用调度源计时器(可以为后台队列调度的计时器,不需要运行循环).

var timer: DispatchSourceTimer!

private func startTimer() {
    let queue = DispatchQueue(label: "com.domain.app.timer")
    timer = DispatchSource.makeTimerSource(queue: queue)
    timer.setEventHandler { [weak self] in
        // do something
    }
    timer.schedule(deadline: .now(), repeating: 1.0)
    timer.resume()
}
Run Code Online (Sandbox Code Playgroud)

有关早期版本Swift的语法,请参阅此答案的上一版本.


Saf*_*ive 9

Timer() 可能不起作用的另一个原因是它的创建方式。我遇到了同样的问题,我尝试的所有方法都没有解决它,包括在主线程上实例化。我盯着这个看了很长时间,直到我意识到(愚蠢地)我正在以不同的方式创造它。代替Timer.scheduledTimer

我实例化它使用

let timer = Timer(timeInterval: 4.0, target: self, selector: #selector(self.timerCompletion), userInfo: nil, repeats: true)
Run Code Online (Sandbox Code Playgroud)

就我而言,我必须将它实际添加到运行循环中才能运行。像这样

RunLoop.main.add(timer, forMode: RunLoop.Mode.default)
Run Code Online (Sandbox Code Playgroud)