使用 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

(以绿色突出显示)

我不确定发生了什么,也无法在文档中找到我理解的任何内容。我该如何解决这个问题?

为了使它正常工作,您需要在这里做几件事。

  1. 您需要将 PHCachingImageManager 作为 属性 缓存在将保持活动状态的对象上。如果您只是创建它而不将其存储在某个地方,ARC 规则将导致它被丢弃。在下面的代码中,我使用了惰性变量,但这不是唯一的方法。
  2. 您应该消除代码中的所有强制解包选项 !。使用 guard let ...if let ... 模式可能感觉打字更多,但它最终会为您节省大量时间和挫败感。将 ! 视为一个危险标志,上面写着“CRASH HERE!”。
  3. 您需要从 resultHandler 完成块设置 AVPlayerItemrequestAVAsset 是异步的,因此它在执行检索资产的潜在昂贵工作时不会阻塞您的主线程。基本上,只要您调用 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)
}

如果有任何不清楚的地方,请告诉我。