【问题标题】:Swift timer won't work after invalidating and reinitiating无效并重新启动后,Swift计时器将不起作用
【发布时间】:2018-05-07 10:08:21
【问题描述】:

我正在使用 Timer() 来指示音频播放器中的当前音频位置

func startTimer() {
        print("PlayerController: startTimer()")
        if itemPlayTimer != nil {
            return
        }
        itemPlayTimer = Timer.scheduledTimer(timeInterval: 0.001,
                                                  target: self,
                                                  selector: #selector(updateItemPlayerTimer),
                                                  userInfo: nil,
                                                  repeats: true)
    }

 @objc func updateItemPlayerTimer() {
        guard let currentTime = player?.currentTime else {
            return
        }
        updateTimeDescription?(currentTime)
    }

当用户暂停播放器应用使计时器失效时

func stopTimer() {
        itemPlayTimer?.invalidate()
        itemPlayTimer = nil
    }

但是在再次调用 startTimer() 之后选择器不会调用

【问题讨论】:

  • 试试这个,Timer(timeInterval: 0.001, target: self, selector: #selector(updateItemPlayerTimer), userInfo: nil, repeats: true)
  • 尝试将时间从 0.001 增加到 0.1
  • 还是不行。第二次调用 startTimer() 方法,定时器启动,但选择器没有调用
  • 什么时候再次调用启动计时器?并检查您的播放器?当第二次选择器触发时,currentTime 是否为零
  • 检查此答案以正确实施计时器stackoverflow.com/a/34509335/7698092

标签: ios swift timer nstimer


【解决方案1】:

原因是计时器开始在其他线程中执行,而不是在主线程中。

【讨论】:

  • 你是怎么知道的?
  • 我将定时器启动代码直接放到 Dispatch.Queue.main{ } 中,它可以工作,然后我找到了启动定时器代码在额外队列中调用的部分代码并修复它
【解决方案2】:

以这种方式改变你的功能:

func startTimer() {
        print("PlayerController: startTimer()")
        if itemPlayTimer == nil {
            itemPlayTimer = Timer.scheduledTimer(timeInterval: 0.001,
                                                  target: self,
                                                  selector: #selector(updateItemPlayerTimer),
                                                  userInfo: nil,
                                                  repeats: true)
        }

}

@objc func updateItemPlayerTimer() {
    guard let currentTime = player?.currentTime else {
        return
    }
    updateTimeDescription?(currentTime)
}

func stopTimer() {
    if itemPlayTimer != nil {
        itemPlayTimer?.invalidate()
        itemPlayTimer = nil
    }
}

【讨论】:

  • 感谢您的回答,但它仍然不起作用...在第二次调用方法 startTimer() 时,定时器启动,但选择器没有调用
  • 那么它应该可以正常工作,检查你的播放器是否为nil
  • 播放器正常,正在播放音频,但音频进度卡住了
【解决方案3】:

使用以下代码。我使用了一个带有示例视频的 AVPlayer 来演示使用 Timer 暂停/播放。音频播放器的逻辑相同。 只需将 AVPlayer 替换为您的 audioPlayer。

这里的关键逻辑是正确管理播放/未播放的状态以及检查计时器是否为零等。

Answer所示

startTimer() 仅当它为 nil 并且 stopTimer() 停止时才启动计时器 仅当它不为零时。

您只需要在之前停止计时器 创建/开始一个新的。

我在一个示例项目中实现了这个并且100%工作

  • 仔细看函数pauseTapped(_ sender: UIButton)
  • 参见代码末尾的示例 gif

import UIKit
import AVKit

class TimerVC: UIViewController {

  ///A container view for displaying the AVPlayer.
  @IBOutlet weak var playerView: UIView!
  /// A button to play and pause the video
  @IBOutlet weak var btnPause: UIButton!

  ///to maintain the status of AVPlayer playing or not
  var flagPlaying = true
  ///An AVPlayer for displaying and playing the video
  var player: AVPlayer?
  ///to show the current time to user
  @IBOutlet weak var lblCurrentTime: UILabel!

  override func viewDidLoad() {

    super.viewDidLoad()
    //add an AVPlayer with sample URL link
    addVideoPlayer( playerView: playerView)

  }
  ///Timer
  var itemPlayTimer: Timer?
  @objc func startTimer() {

    if itemPlayTimer != nil {
      return
    }
    itemPlayTimer = Timer.scheduledTimer(timeInterval: 0.001,
                                         target: self,
                                         selector: #selector(updateItemPlayerTimer),
                                         userInfo: nil,
                                         repeats: true)
  }

  ///update time label
  @objc func updateItemPlayerTimer() {
    guard let currentTime = player?.currentTime else {
      return
    }

    updateTimeDescription(currentTime())
  }

  func updateTimeDescription( _ currentTime :CMTime ) {
    self.lblCurrentTime.text = "\(currentTime.seconds)"
  }

  ///To Pause and play the video
  @IBAction func pauseTapped(_ sender: UIButton) {
    if flagPlaying {
      //pause
      if itemPlayTimer != nil {
        player?.pause()
        itemPlayTimer?.invalidate()
        itemPlayTimer = nil
        flagPlaying = false

        DispatchQueue.main.async {
          self.btnPause.setTitle("Play", for: .normal)
        }

      }

    }else {
      //not playing
      if itemPlayTimer == nil {
        player?.play()
        startTimer()

        flagPlaying = true
        DispatchQueue.main.async {
          self.btnPause.setTitle("Pause", for: .normal)
        }

      }

    }

  }

  private func addVideoPlayer(playerView: UIView) {

    //let playerItem = AVPlayerItem(asset: asset)
    player = AVPlayer.init(url: URL.init(string: "http://techslides.com/demos/sample-videos/small.mp4")!)


    let layer: AVPlayerLayer = AVPlayerLayer(player: player)
    layer.backgroundColor = UIColor.white.cgColor
    layer.frame = CGRect(x: 0, y: 0, width: playerView.frame.width, height: playerView.frame.height)
    layer.videoGravity = AVLayerVideoGravity.resizeAspectFill
    playerView.layer.sublayers?.forEach({$0.removeFromSuperlayer()})
    playerView.layer.addSublayer(layer)

    flagPlaying = true
    player?.play()
    startTimer()
  }


}

工作示例

如果您需要任何帮助,请告诉我

【讨论】:

  • 非常感谢您的回答,但对我来说仍然无法正常工作
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-07-31
  • 1970-01-01
  • 2016-04-03
相关资源
最近更新 更多