使用 PHCachingImageManager().requestAVAsset 时崩溃
Crash when using PHCachingImageManager().requestAVAsset
我正在使用 PHCachingImageManager().requestAVAsset
从相机胶卷加载一些视频:
override func viewDidLoad() {
super.viewDidLoad()
print("SEGUE SUCCESSFUL")
view.backgroundColor = .black
avPlayerLayer = AVPlayerLayer(player: avPlayer)
view.layer.insertSublayer(avPlayerLayer, at: 0)
var asset2:AVAsset? = nil
PHCachingImageManager().requestAVAsset(forVideo: (vidLocation?[videoSender]!)!, options: nil, resultHandler: {(asset: AVAsset?, audioMix: AVAudioMix?, info: [AnyHashable : Any]?) in
asset2 = asset! as AVAsset
})
let playerItem = AVPlayerItem(asset: asset2!)
avPlayer.replaceCurrentItem(with: playerItem)
}
然而,当我 运行 程序暂停在 PHCachingImageManager().requestAVAsset
行并显示:
THREAD 1 : EXC_BREAKPOINT
(以绿色突出显示)
我不确定发生了什么,也无法在文档中找到我理解的任何内容。我该如何解决这个问题?
为了使它正常工作,您需要在这里做几件事。
- 您需要将
PHCachingImageManager
作为 属性 缓存在将保持活动状态的对象上。如果您只是创建它而不将其存储在某个地方,ARC 规则将导致它被丢弃。在下面的代码中,我使用了惰性变量,但这不是唯一的方法。
- 您应该消除代码中的所有强制解包选项
!
。使用 guard let ...
或 if let ...
模式可能感觉打字更多,但它最终会为您节省大量时间和挫败感。将 !
视为一个危险标志,上面写着“CRASH HERE!”。
- 您需要从
resultHandler
完成块设置 AVPlayerItem
。 requestAVAsset
是异步的,因此它在执行检索资产的潜在昂贵工作时不会阻塞您的主线程。基本上,只要您调用 requestAVAsset
,就会有一个单独的线程运行并为您工作,而主线程会继续处理 viewDidLoad
方法中的其余代码。当它成功检索到 AVAsset
时,它会回调您最初提供的代码块(在主线程上),以便您可以继续处理。
这是您重写的代码以包含我建议的更改:
lazy var imageManager = {
return PHCachingImageManager()
}()
override func viewDidLoad() {
super.viewDidLoad()
print("SEGUE SUCCESSFUL")
view.backgroundColor = .black
avPlayerLayer = AVPlayerLayer(player: avPlayer)
view.layer.insertSublayer(avPlayerLayer, at: 0)
var asset2:AVAsset? = nil
guard let phAsset = vidLocation?[videoSender] else { return } //No video
imageManager.requestAVAsset(forVideo: phAsset, options: nil, resultHandler: {(asset: AVAsset?, audioMix: AVAudioMix?, info: [AnyHashable : Any]?) in
if let avAsset = asset {
self.play(asset: avAsset)
}
})
func play(asset: AVAsset) {
let playerItem = AVPlayerItem(asset: asset)
avPlayer.replaceCurrentItem(with: playerItem)
}
如果有任何不清楚的地方,请告诉我。
我正在使用 PHCachingImageManager().requestAVAsset
从相机胶卷加载一些视频:
override func viewDidLoad() {
super.viewDidLoad()
print("SEGUE SUCCESSFUL")
view.backgroundColor = .black
avPlayerLayer = AVPlayerLayer(player: avPlayer)
view.layer.insertSublayer(avPlayerLayer, at: 0)
var asset2:AVAsset? = nil
PHCachingImageManager().requestAVAsset(forVideo: (vidLocation?[videoSender]!)!, options: nil, resultHandler: {(asset: AVAsset?, audioMix: AVAudioMix?, info: [AnyHashable : Any]?) in
asset2 = asset! as AVAsset
})
let playerItem = AVPlayerItem(asset: asset2!)
avPlayer.replaceCurrentItem(with: playerItem)
}
然而,当我 运行 程序暂停在 PHCachingImageManager().requestAVAsset
行并显示:
THREAD 1 : EXC_BREAKPOINT
(以绿色突出显示)
我不确定发生了什么,也无法在文档中找到我理解的任何内容。我该如何解决这个问题?
为了使它正常工作,您需要在这里做几件事。
- 您需要将
PHCachingImageManager
作为 属性 缓存在将保持活动状态的对象上。如果您只是创建它而不将其存储在某个地方,ARC 规则将导致它被丢弃。在下面的代码中,我使用了惰性变量,但这不是唯一的方法。 - 您应该消除代码中的所有强制解包选项
!
。使用guard let ...
或if let ...
模式可能感觉打字更多,但它最终会为您节省大量时间和挫败感。将!
视为一个危险标志,上面写着“CRASH HERE!”。 - 您需要从
resultHandler
完成块设置AVPlayerItem
。requestAVAsset
是异步的,因此它在执行检索资产的潜在昂贵工作时不会阻塞您的主线程。基本上,只要您调用requestAVAsset
,就会有一个单独的线程运行并为您工作,而主线程会继续处理viewDidLoad
方法中的其余代码。当它成功检索到AVAsset
时,它会回调您最初提供的代码块(在主线程上),以便您可以继续处理。
这是您重写的代码以包含我建议的更改:
lazy var imageManager = {
return PHCachingImageManager()
}()
override func viewDidLoad() {
super.viewDidLoad()
print("SEGUE SUCCESSFUL")
view.backgroundColor = .black
avPlayerLayer = AVPlayerLayer(player: avPlayer)
view.layer.insertSublayer(avPlayerLayer, at: 0)
var asset2:AVAsset? = nil
guard let phAsset = vidLocation?[videoSender] else { return } //No video
imageManager.requestAVAsset(forVideo: phAsset, options: nil, resultHandler: {(asset: AVAsset?, audioMix: AVAudioMix?, info: [AnyHashable : Any]?) in
if let avAsset = asset {
self.play(asset: avAsset)
}
})
func play(asset: AVAsset) {
let playerItem = AVPlayerItem(asset: asset)
avPlayer.replaceCurrentItem(with: playerItem)
}
如果有任何不清楚的地方,请告诉我。