【问题标题】:AVCaptureSession stopRunning() Mysterious CrashAVCaptureSession stopRunning() 神秘崩溃
【发布时间】:2021-06-02 18:36:28
【问题描述】:

最近我收到有关 firebase 崩溃的通知,这是消息:

[AVCaptureSession stopRunning] stopRunning may not be called between calls to beginConfiguration and commitConfiguration 

我检查了我的代码,最奇怪的是我从不打电话,也没有提到 beginConfiguration()commitConfiguration()

在我的CameraManager 类中,这是触发崩溃的函数,它在 deinit 上调用:

  func stop() {
    guard isStarted else { return Log.w("CameraManager wasn't started") }
    queue.async {
        self.isStarted = false
        self.isCapturingFrame = false
        self.isCapturingCode = false
        self.session?.stopRunning()
        self.session = nil
        self.device = nil
    }
    notificationCenter.removeObserver(self, name: UIApplication.didBecomeActiveNotification, object: nil)
    layer.removeFromSuperlayer()
    layer.session = nil
}

queue 只是一个串行调度队列。 无论我尝试什么,我都无法重现此崩溃。 尝试拉菜单、推送通知、打电话、模拟内存警告等... 澄清一下,我的代码中没有一个地方调用 beginConfigurationcommitConfiguration

【问题讨论】:

    标签: ios avfoundation avcapturesession


    【解决方案1】:

    我可以想象layer.session = nil 将导致重新配置捕获会话(因为删除了与预览层的连接)。而且由于您正在调用 stopRunning() async,我猜您可能会遇到在配置更改中间调用 stopRunning() 的竞争条件。

    我建议您尝试使清理调用同步 (queue.sync { ... }) 或将层清理也移动到 async 块中。

    【讨论】:

    • 这很有趣!通过调用 layer.session = nil 会触发隐式配置更改?值得尝试通过子类化,谢谢!
    • 是的,因为该层连接到捕获会话的输出端口。 setter 可以方便地为您添加/删除该连接,但这始终需要锁定会话以进行配置。