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

时间:2016-07-02 20:15:40

标签: ios swift swift3

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

$scope.playPage = function(data){
     console.log(data);
     //$http.post(url, data, config);
};

$scope.gameBoardDto = {
    player1:"0",
    player2:"0",
    topleft:".",
    ...
    ...
};

$http({
        method: 'POST',
        url: 'http://localhost:8080/play',
        data: $scope.gameBoardDto,
        headers: {'Content-Type': 'application/json;charset=UTF-8'}
    ...

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

该块是在获得self.timer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(self.foo), userInfo: nil, repeats: true) 相关信息的许可后调用的完成处理程序。

3 个答案:

答案 0 :(得分:45)

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

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

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

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

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

有关早期版本Swift的语法,请参阅previous revision of this answer

答案 1 :(得分:1)

Timer()可能无法正常工作的另一个原因是它的创建方式。我有同样的问题,我尝试过的所有方法都没有解决,包括在主线程上实例化。我凝视了好一阵子,直到我(愚蠢地)意识到我正在以不同的方式创建它。代替Timer.scheduledTimer

我使用

实例化了它

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

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

RunLoop.main.add(timer, forMode: RunLoop.Mode.default)

答案 2 :(得分:0)

这听起来似乎很明显,但是我有一个类似的问题,计时器不会触发,原因是它不在主线程中……没有错误,只是从未触发过。

放入主线程,至少您可以尝试一下!

 DispatchQueue.main.async {
  //insert your timer here
}