Ios 如果URL失败,如何重新加载AVPlayer的数据
我有一个json文件,其中包含一些单词的URL(带.mp3)。一些URL无效(或有效,但返回错误,因此我无法获取数据) 这个URL我用来播放单词的发音。因此,我将抛出3个步骤:Ios 如果URL失败,如何重新加载AVPlayer的数据,ios,swift,multithreading,avplayer,Ios,Swift,Multithreading,Avplayer,我有一个json文件,其中包含一些单词的URL(带.mp3)。一些URL无效(或有效,但返回错误,因此我无法获取数据) 这个URL我用来播放单词的发音。因此,我将抛出3个步骤: 查找特定单词的URL。如果找不到,就什么事也没有发生 使用此URL初始化AVPlayerItem并准备AVPlayer。而不仅仅是等待,当用户按下 当用户按下word时播放声音 所以,首先,我正在准备我的AVPlayer,以避免延迟播放 我对多线程有点困惑,我不知道应该在哪里检查我是否能够播放这个声音,我应该使用下一个U
"abel": [
"http://static.sfdict.com/staticrep/dictaudio/A00/A0015900.mp3",
"http://img2.tfd.com/pron/mp3/en/US/d5/d5djdgdyslht.mp3",
"http://img2.tfd.com/pron/mp3/en/UK/d5/d5djdgdyslht.mp3",
"http://www.yourdictionary.com/audio/a/ab/abel.mp3"
],
"abele": [
"http://www.yourdictionary.com/audio/a/ab/abele.mp3",
"http://static.sfdict.com/staticrep/dictaudio/A00/A0016300.mp3",
"http://www.oxforddictionaries.com/media/english/uk_pron/a/abe/abele/abele__gb_2_8.mp3",
"http://s3.amazonaws.com/audio.vocabulary.com/1.0/us/A/1B3JGI7ALNB2K.mp3",
"http://www.oxforddictionaries.com/media/english/uk_pron/a/abe/abele/abele__gb_1_8.mp3"
],
所以,我需要获取第一个URL并检查它。如果失败,则再进行一次检查。。。等等,当URL结束时,或者找到一些有效的URL。
所有这些都必须在AVPlayer尝试播放声音之前完成
如何实施,在哪里实施
请用简单的话告诉并描述解析,因为我是swift和多线程的初学者。我会使用
AVPlayerItem.Status
属性查看解析失败的时间。在当前代码中,您在创建项目后立即检查状态,该项目将始终产生与您初始化AVPlayerItem
时相同的结果。默认情况下,状态
未知
一旦您与播放器关联,AVPlayerItem
就会进入队列。为了能够跟踪状态更改,您需要设置一个观察者
文档仍然建议使用addObserver
使用“旧样式”,但根据您的偏好,我会选择较新的块样式
// make sure to keep a strong reference to the observer (e.g. in your controller) otherwise the observer will be de-initialised and no changes updates will occur
var observerStatus: NSKeyValueObservation?
// in your method where you setup your player item
observerStatus = playerItem.observe(\.status, changeHandler: { (item, value) in
debugPrint("status: \(item.status.rawValue)")
if item.status == .failed {
// enqueue new asset with diff url
}
})
您还可以在AVPlayer
实例上设置类似的观察者
更新了完整示例 -这段代码远非完美,但它展示了observer的优点
import UIKit
import AVFoundation
class ViewController: UIViewController {
var observerStatus: NSKeyValueObservation?
var currentTrack = -1
let urls = [
"https://sample-videos.com/audio/mp3/crowd-cheerin.mp3", // "https://sample-videos.com/audio/mp3/crowd-cheering.mp3"
"https://sample-videos.com/audio/mp3/wave.mp3"
]
var player: AVPlayer? {
didSet {
guard let p = player else { return debugPrint("no player") }
debugPrint("status: \(p.currentItem?.status == .unknown)") // this is set before status changes from unknown
}
}
override func viewDidLoad() {
super.viewDidLoad()
nextTrack()
}
func nextTrack() {
currentTrack += 1
guard let url = URL(string: urls[currentTrack]) else { return }
let item = AVPlayerItem(url: url)
observerStatus = item.observe(\.status, changeHandler: { [weak self] (item, value) in
switch item.status {
case .unknown:
debugPrint("status: unknown")
case .readyToPlay:
debugPrint("status: ready to play")
case .failed:
debugPrint("playback failed")
self?.nextTrack()
}
})
if player == nil {
player = AVPlayer(playerItem: item)
} else {
player?.replaceCurrentItem(with: item)
}
player?.play()
}
}
我将使用
AVPlayerItem.Status
属性查看它何时失败。在当前代码中,您在创建项目后立即检查状态,该项目将始终产生与您初始化AVPlayerItem
时相同的结果。默认情况下,状态
未知
一旦您与播放器关联,AVPlayerItem
就会进入队列。为了能够跟踪状态更改,您需要设置一个观察者
文档仍然建议使用addObserver
使用“旧样式”,但根据您的偏好,我会选择较新的块样式
// make sure to keep a strong reference to the observer (e.g. in your controller) otherwise the observer will be de-initialised and no changes updates will occur
var observerStatus: NSKeyValueObservation?
// in your method where you setup your player item
observerStatus = playerItem.observe(\.status, changeHandler: { (item, value) in
debugPrint("status: \(item.status.rawValue)")
if item.status == .failed {
// enqueue new asset with diff url
}
})
您还可以在AVPlayer
实例上设置类似的观察者
更新了完整示例 -这段代码远非完美,但它展示了observer的优点
import UIKit
import AVFoundation
class ViewController: UIViewController {
var observerStatus: NSKeyValueObservation?
var currentTrack = -1
let urls = [
"https://sample-videos.com/audio/mp3/crowd-cheerin.mp3", // "https://sample-videos.com/audio/mp3/crowd-cheering.mp3"
"https://sample-videos.com/audio/mp3/wave.mp3"
]
var player: AVPlayer? {
didSet {
guard let p = player else { return debugPrint("no player") }
debugPrint("status: \(p.currentItem?.status == .unknown)") // this is set before status changes from unknown
}
}
override func viewDidLoad() {
super.viewDidLoad()
nextTrack()
}
func nextTrack() {
currentTrack += 1
guard let url = URL(string: urls[currentTrack]) else { return }
let item = AVPlayerItem(url: url)
observerStatus = item.observe(\.status, changeHandler: { [weak self] (item, value) in
switch item.status {
case .unknown:
debugPrint("status: unknown")
case .readyToPlay:
debugPrint("status: ready to play")
case .failed:
debugPrint("playback failed")
self?.nextTrack()
}
})
if player == nil {
player = AVPlayer(playerItem: item)
} else {
player?.replaceCurrentItem(with: item)
}
player?.play()
}
}
解决方案:
private var player: AVPlayer? {
didSet{
if player?.currentItem?.status == .failed {
if indexOfURL >= 0 {
prepareForPronunciation(indexOfURL)
}
}
}
}
如果URL已结束,请将indexOfURL设置为-1,否则将其递增以在下一个函数调用中使用下一个URL解决方案:
private var player: AVPlayer? {
didSet{
if player?.currentItem?.status == .failed {
if indexOfURL >= 0 {
prepareForPronunciation(indexOfURL)
}
}
}
}
如果URL已结束,请将indexOfURL设置为-1,否则将其递增以在下一个函数调用中使用下一个URL谢谢您的解决方案。事实上,在我的知识中有一些空白的代码。因此,我将尝试更多地了解观察。我通过观察AVPlayer解决了这个问题。我会把我的解决方案写在下面。谢谢你的解决方案。事实上,在我的知识中有一些空白的代码。因此,我将尝试更多地了解观察。我通过观察AVPlayer解决了这个问题。我会在下面写下我的解决方案。我相信你的解决方案不会像你期望的那样有效。在使用现场文件时可能不复制,但使用远程URL需要考虑延迟。当
AVPlayerItem
的状态改变时,您的播放器将已经设置好。此外,除非您有理由这样做,否则没有理由为每个项目重新创建AVPlayer
,而是重复使用它。我已经更新了我的答案。我相信你的解决方案不会像你期望的那样有效。在使用现场文件时可能不复制,但使用远程URL需要考虑延迟。当AVPlayerItem
的状态改变时,您的播放器将已经设置好。此外,除非您有理由这样做,否则没有理由为每个项目重新创建AVPlayer
,而是重复使用它。我已经更新了我的答案。