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()
}
}
工作示例
如果您需要任何帮助,请告诉我
原因是定时器开始在其他线程中执行,而不是在主线程中。
我正在使用 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()
}
}
工作示例
如果您需要任何帮助,请告诉我
原因是定时器开始在其他线程中执行,而不是在主线程中。