ios - AVAssetTrack 的 Assets 属性有时为零

标签 ios asynchronous avfoundation avasset

我试图从 AVAssetTrack 对象获取 asset 属性,但有时它是 nil。似乎只有在我使用 Dispatch.main.async 之后才会出现问题。

根据documentation ,需要使用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
        // [...]
    }
}

我发现的是:

  • 无论我是在设备上运行还是在 模拟器。
  • 这似乎不是视频/videoURL 的问题。 该视频是主包的一部分,我尝试了 .mp4 和 .mov 文件,我通过 AVPlayerViewController。

这是一个有效的 demo project .

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

注意:在阅读 Matt 的有用评论和进一步调查后编辑了这个问题。

最佳答案

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

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

好的,但现在请仔细看我表演一个惊人的把戏:

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

哇哦!我所做的只是添加一个 print 语句——现在突然之间完全相同的断言通过了。这实际上与您的原始陈述(您后来将其删除)平行,即“使用调试器单步执行代码时,有时问题消失了。”

所以,现在,我的怀疑彻底被激起了,我做了一件难以置信的聪明事(即使我自己这么说)。我删除了 print(asset),但我将方案的配置从 Debug 切换为 Release。很快,断言仍然通过。

那么您发现的是编译器的一个怪癖——我敢称之为错误吗?

等等,还有更多。您很合理地问,为什么 asset 是可选的。这是因为它:

weak open var asset: AVAsset? { get }

这就是你的答案。该轨道对其 Assets 的引用很弱。如果我们将轨道向下传递到异步队列中,并且我们将 Assets 本身与我们一起使用,那么弱引用就会消失, Assets 就会丢失——在调试构建中。

希望这对您有所帮助。您可能正在等待我就这是否构成错误做出一些宏大的结论性声明,但我不会,抱歉。我提供了两种解决方法(使用 Release 版本,或者故意将 Assets 引用带入异步队列),这是我所能做到的。

关于ios - AVAssetTrack 的 Assets 属性有时为零,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55710126/

相关文章:

ios - 尝试将 ManagedObjectContext 从 GameAppDelegate 传递到嵌入在 NavigationController 中的 View

ios - 视网膜显示中来自 openstreetmap 的图 block

JavaScript 异步循环

swift AV基金会: QRcode scanning error in bright ambient

ios - 如何隐藏和取消隐藏 UIAlertView。?

ios - 将颜色加深限制在 CGPath 的内部

c# - 如何确保任务已启动并在未启动时安全地启动它?

javascript - 如何使用 Firebase 对 HTML 进行异步更新

ios - 原深感相机像素距离不准确

iphone - 连续调用 startRecordingToOutputFileURL :