使用计时器时,UI处于暂停状态

时间:2018-03-18 13:32:34

标签: ios swift grand-central-dispatch nstimer mpmediaplayercontroller

我正在使用计时器重复每秒来更新正在播放的currentPlaybackTime,所以我每秒都用当前歌曲的进度更新我的标签。 我以前使用NSTimer或在Swift a Timer中重复每一秒,但是当我更改歌曲或开始和停止一首歌时,我遇到了问题,秒标签会滞后(它是' d保持相同状态5秒钟,同时听到播放的歌曲,然后更新到正确的时间)。 然后我继续使用GCD,即使在后台队列中我也有同样的问题。然后我去使用DispatchSourceTimer,我得到了以下日志:

Fired: 2018-03-18 13:22:17 +0000
Timer fired: 2018-03-18 13:22:17 +0000
Fired: 2018-03-18 13:22:18 +0000
Timer fired: 2018-03-18 13:22:18 +0000
Fired: 2018-03-18 13:22:19 +0000
Fired: 2018-03-18 13:22:20 +0000
Timer fired: 2018-03-18 13:22:20 +0000
Fired: 2018-03-18 13:22:21 +0000
Fired: 2018-03-18 13:22:22 +0000
Fired: 2018-03-18 13:22:23 +0000
Fired: 2018-03-18 13:22:24 +0000
Fired: 2018-03-18 13:22:25 +0000
Fired: 2018-03-18 13:22:26 +0000
Fired: 2018-03-18 13:22:27 +0000
Fired: 2018-03-18 13:22:28 +0000
Fired: 2018-03-18 13:22:29 +0000
Fired: 2018-03-18 13:22:30 +0000
Timer fired: 2018-03-18 13:22:30 +0000
Timer fired: 2018-03-18 13:22:30 +0000
Timer fired: 2018-03-18 13:22:30 +0000
Timer fired: 2018-03-18 13:22:30 +0000
Timer fired: 2018-03-18 13:22:30 +0000
Timer fired: 2018-03-18 13:22:30 +0000
Timer fired: 2018-03-18 13:22:30 +0000
Timer fired: 2018-03-18 13:22:30 +0000
Timer fired: 2018-03-18 13:22:30 +0000
Timer fired: 2018-03-18 13:22:30 +0000
Timer fired: 2018-03-18 13:22:30 +0000
Fired: 2018-03-18 13:22:31 +0000
Timer fired: 2018-03-18 13:22:31 +0000
Fired: 2018-03-18 13:22:32 +0000
Timer fired: 2018-03-18 13:22:32 +0000

那个说"被解雇的"是DispatchSourceTimer的实际偶数处理程序,而#34;定时器被触发"是在更新标签等的处理函数内。很明显,你可以看到计时器工作正常,但似乎主线程被大量使用。

这是我的代码:

//timer is a DispatchSourceTimer, queue is a concurrent custom queue
public func startTimer() {
    timer?.cancel()
    timer = DispatchSource.makeTimerSource(queue: queue)
    timer?.schedule(deadline: DispatchTime.now(), repeating: .seconds(1))
    timer?.setEventHandler { [weak self] in
        print("Fired: \(Date())")
        DispatchQueue.main.async {
            self?.notifyObservers()
        }
    }
    timer?.resume()
}

public func stopTimer() {
    timer?.cancel()
    timer = nil
}

这是通知观察员:

private func notifyObservers() {
    for observer: TimeObserver in self.timeObservers {
        observer.timerFired()
    }
}

我维护一个观察者对象数组,希望得到计时器触发的通知。

我做了一个测试并删除了for循环,只是通知了列表中的第一个观察者,它确实加快了一些速度,但仍然没有解决问题。

如果我只是播放这首歌,几秒钟之后主线程实际上可以处理它并且我可以完美地显示时间,但是在做重的事情时,例如使用MPMediaPlayer框架来改变歌曲或者在调用时<{1}}上的play()pause()开始滞后。

任何帮助将不胜感激。谢谢。

1 个答案:

答案 0 :(得分:0)

如果您像这样实例化播放器,则可以看到此行为:

let player = MPMusicPlayerController()

但如果你使用的话,你不会看到这种延迟(或者至少它会更少):

let player = MPMusicPlayerController.applicationQueuePlayer

或:

let player = MPMusicPlayerController.applicationMusicPlayer

在我的iPhone X上,我使用前一种技术经历了5-8秒的主线程阻塞,但后两种技术只用了一秒或更少。

我认为你的调度计时器是为了测试发生了什么,但是如果它所做的就是将它发送回主要的话,那么在后台线程上使用这个调度计时器是没有意义的。队列。如果您的主要线程因您无法控制的原因而被阻止,则您不希望通过一系列未及时处理的更新来阻止主线程。

我建议还原为简单的Timer