AVAssetTrack 的 Asset 属性有时为零

Goo*_*rel 5 asynchronous avfoundation ios avasset

我试图assetAVAssetTrack对象中获取属性,但nil有时会这样。看来这个问题是我使用后才出现的Dispatch.main.async

根据文档,有必要使用loadValuesAsynchronously(forKeys:, completion:)以避免阻塞主线程,并在加载完成后返回主线程。

let asset = AVURLAsset(url: videoInAppBundleURL)
let track = asset.tracks(withMediaType: .video).first!
assert(track.asset != nil) // passes
track.loadValuesAsynchronously(forKeys: [#keyPath(AVAssetTrack.asset)]) {
    assert(track.asset != nil) // passes
    DispatchQueue.main.async {
        assert(track.asset != nil) // FAILS
        // [...]
    }
}
Run Code Online (Sandbox Code Playgroud)

我发现的是:

  • 无论我是在设备上还是在模拟器上运行都没有区别。
  • 看来不是video/videoURL的问题。该视频是主包的一部分,我尝试了 .mp4 和 .mov 文件,并通过 AVPlayerViewController 显示视频来确保视频正常工作。

这是一个工作演示项目

我还想知道:为什么AVAssetTrackasset属性是可选的?(所有!!其他属性都是非可选的)

注意:在阅读马特的有用评论和进一步调查后,这个问题已被编辑。

mat*_*att 6

我重现了这个问题,并对你的 github 示例进行了一些调整,如下所示:

\n\n
    let asset = AVURLAsset(url: videoInAppBundleURL)\n    let tracksKey = #keyPath(AVAsset.tracks)\n    asset.loadValuesAsynchronously(forKeys: [tracksKey]) {\n        let track = asset.tracks(withMediaType: .video).first!\n        DispatchQueue.main.async {\n            assert(track.asset != nil) // fails\n        }\n    }\n
Run Code Online (Sandbox Code Playgroud)\n\n

好的,但现在请仔细观看我表演一个惊人的技巧:

\n\n
    let asset = AVURLAsset(url: videoInAppBundleURL)\n    let tracksKey = #keyPath(AVAsset.tracks)\n    asset.loadValuesAsynchronously(forKeys: [tracksKey]) {\n        let track = asset.tracks(withMediaType: .video).first!\n        DispatchQueue.main.async {\n            print(asset) // <-- amazing trick\n            assert(track.asset != nil) // passes!\n        }\n    }\n
Run Code Online (Sandbox Code Playgroud)\n\n

哇!我所做的只是添加一条print语句 \xe2\x80\x94 ,现在突然相同的断言通过了。事实上,这与您最初的声明(您后来将其删除)平行:“有时,当使用调试器单步执行代码时,问题就消失了。\xe2\x80\x9d

\n\n

所以,现在,我的怀疑被彻底激起,我做了一件令人难以置信的聪明事(即使我自己这么说)。我删除了print(asset),但我将 schema\xe2\x80\x99s 配置从 Debug 切换到 Release。转眼间,这个断言仍然成立。

\n\n

那么你\xe2\x80\x99ve发现的是编译器\xe2\x80\x94的一个怪癖,我敢称之为错误吗?

\n\n

但是等等,还有\xe2\x80\x99s。你问的很合理,为什么asset是可选的。它\xe2\x80\x99s 因为它\xe2\x80\x99s weak

\n\n
weak open var asset: AVAsset? { get }\n
Run Code Online (Sandbox Code Playgroud)\n\n

这就是你的答案。该曲目对其资产的引用很弱。如果我们将轨道传递到异步队列中,并且不将资产本身带入,那么弱引用就会消失,并且资产会在调试构建中丢失\xe2\x80\x94。

\n\n

希望这可以帮助。您可能正在等待我就这是否构成错误做出一些宏大的结论性陈述,但抱歉,我\xe2\x80\x99m 不会这样做。我\xe2\x80\x99ve提供了两种解决方法(使用发布版本,或故意将资产引用放入异步队列中),并且\xe2\x80\x99s尽我所能。

\n