Swift 计时器在无效和重新启动后将无法工作

Swift timer won't work after invalidating and reinitiating

我正在使用 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() 之后选择器不会调用

以这种方式更改您的功能:

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

使用以下代码。我使用带有示例视频的 AVPlayer 来演示 pausing/playing 与计时器。音频播放器的逻辑相同。 只需将 AVPlayer 替换为您的 audioPlayer。

这里的关键逻辑是正确管理 Playing/not 播放和检查定时器的状态是否为 nil 等

如本文所示

startTimer() starts the timer only if it's nil and stopTimer() stops it only if it's not nil.

You have only to take care of stopping the timer before creating/starting a new one.

我已经在示例项目中实现了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({[=10=].removeFromSuperlayer()})
    playerView.layer.addSublayer(layer)

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


}

工作示例

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

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