AVPlayer.status 不 运行 包裹在带有延迟的 DispatchWorkItem 中
AVPlayer.status doesn't run when wrapped in a DispatchWorkItem with a Delay
因为我在单元格中播放视频,所以我有一个 AVPlayer 可以在某些情况下立即播放视频,而在其他情况下它会在几秒钟后播放。当它立即运行时 .status
工作正常。但是,当我将它包装在 DispatchWorkItem
中并带有 .asyncAfter
延迟时,永远不会调用完全相同的 .status
。我也尝试使用 perform(_:, with:, afterDelay:)
和 Timer
但这也不起作用。
var player: AVPlayer?
var playerItem: AVPlayerItem?
var observer: NSKeyValueObservation? = nil
var workItem: DispatchWorkItem? = nil
var startImmediately = false
var timer: Timer?
viewDidLoad() {
// add asset to playerItem, add playerItem to player ...
}
func someCircumstance() {
if startImmediately {
setNSKeyValueObserver() // this works fine and .status is called
} else {
createWorkItem()
DispatchQueue.main.asyncAfter(deadline: .now() + 0.33, execute: executeWorkItem) // this delay runs but .status is never called
// perform(#selector(executeWorkItem), with: nil, afterDelay: 0.33) // same issue
// timer = Timer.scheduledTimer(timeInterval: 0.33, target: self, selector: #selector(executeWorkItem), userInfo: nil, repeats: false) // same issue
// RunLoop.current.add(timer!, forMode: .common)
}
}
func createWorkItem() {
workItem = DispatchWorkItem {
DispatchQueue.main.async { [weak self] in
self?.setNSKeyValueObserver()
}
}
}
@objc func executeWorkItem() {
guard let workItem = workItem else { return }
workItem.perform()
}
func setNSKeyValueObserver() {
// without a long explanation this sometimes has to start with a delay because of scrolling reason I also might have to cancel it
observer = player?.observe(\.status, options: [.new, .old]) { [weak self] (player, change) in
switch (player.status) {
case .readyToPlay:
print("Media Ready to Play")
case .failed, .unknown:
print("Media Failed to Play")
@unknown default:
print("Unknown Error")
}
}
}
我也尝试使用较旧的 KVO API .status 观察器,但是在使用延迟时出现了同样的问题
private var keepUpContext = 0
viewDidLoad() {
// add asset to playerItem, add playerItem to player ...
player?.addObserver(self, forKeyPath: "currentItem.playbackLikelyToKeepUp", options: [.old, .new], context: &keepUpContext)
}
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
if context == &keepUpContext {
if let player = player, let item = player.currentItem, item.isPlaybackLikelyToKeepUp {
print("Media Ready to Play")
}
}
}
问题似乎是延迟。
更新
我刚刚尝试了以下代码,但它也不起作用:
if startImmediately {
setNSKeyValueObserver()
} else {
DispatchQueue.main.asyncAfter(deadline: .now() + 0.15) { [weak self] in
self?.setNSKeyValueObserver()
}
}
能否尝试将 forKeyPath
参数值更改为 #keyPath(AVPlayerItem.status)
您似乎是在播放器加载内容后添加观察者。它可能在 viewDidLoad
和延迟之间加载。如果在添加观察者时将 .initial
添加到选项列表,即使玩家已经准备好,您也一定会收到状态通知。
因为我在单元格中播放视频,所以我有一个 AVPlayer 可以在某些情况下立即播放视频,而在其他情况下它会在几秒钟后播放。当它立即运行时 .status
工作正常。但是,当我将它包装在 DispatchWorkItem
中并带有 .asyncAfter
延迟时,永远不会调用完全相同的 .status
。我也尝试使用 perform(_:, with:, afterDelay:)
和 Timer
但这也不起作用。
var player: AVPlayer?
var playerItem: AVPlayerItem?
var observer: NSKeyValueObservation? = nil
var workItem: DispatchWorkItem? = nil
var startImmediately = false
var timer: Timer?
viewDidLoad() {
// add asset to playerItem, add playerItem to player ...
}
func someCircumstance() {
if startImmediately {
setNSKeyValueObserver() // this works fine and .status is called
} else {
createWorkItem()
DispatchQueue.main.asyncAfter(deadline: .now() + 0.33, execute: executeWorkItem) // this delay runs but .status is never called
// perform(#selector(executeWorkItem), with: nil, afterDelay: 0.33) // same issue
// timer = Timer.scheduledTimer(timeInterval: 0.33, target: self, selector: #selector(executeWorkItem), userInfo: nil, repeats: false) // same issue
// RunLoop.current.add(timer!, forMode: .common)
}
}
func createWorkItem() {
workItem = DispatchWorkItem {
DispatchQueue.main.async { [weak self] in
self?.setNSKeyValueObserver()
}
}
}
@objc func executeWorkItem() {
guard let workItem = workItem else { return }
workItem.perform()
}
func setNSKeyValueObserver() {
// without a long explanation this sometimes has to start with a delay because of scrolling reason I also might have to cancel it
observer = player?.observe(\.status, options: [.new, .old]) { [weak self] (player, change) in
switch (player.status) {
case .readyToPlay:
print("Media Ready to Play")
case .failed, .unknown:
print("Media Failed to Play")
@unknown default:
print("Unknown Error")
}
}
}
我也尝试使用较旧的 KVO API .status 观察器,但是在使用延迟时出现了同样的问题
private var keepUpContext = 0
viewDidLoad() {
// add asset to playerItem, add playerItem to player ...
player?.addObserver(self, forKeyPath: "currentItem.playbackLikelyToKeepUp", options: [.old, .new], context: &keepUpContext)
}
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
if context == &keepUpContext {
if let player = player, let item = player.currentItem, item.isPlaybackLikelyToKeepUp {
print("Media Ready to Play")
}
}
}
问题似乎是延迟。
更新
我刚刚尝试了以下代码,但它也不起作用:
if startImmediately {
setNSKeyValueObserver()
} else {
DispatchQueue.main.asyncAfter(deadline: .now() + 0.15) { [weak self] in
self?.setNSKeyValueObserver()
}
}
能否尝试将 forKeyPath
参数值更改为 #keyPath(AVPlayerItem.status)
您似乎是在播放器加载内容后添加观察者。它可能在 viewDidLoad
和延迟之间加载。如果在添加观察者时将 .initial
添加到选项列表,即使玩家已经准备好,您也一定会收到状态通知。