dealloc AVCaptureVideoPreviewLayer 期间罕见崩溃

Igo*_*uta 6 crash key-value-observing dealloc ios avcapturesession

在客户端手机上,相机释放期间很少会发生崩溃

Fatal Exception: NSRangeException
Cannot remove an observer <AVCaptureSession 0x174212170> for the key path "changeSeed" from <AVCaptureConnection 0x17420fa60> because it is not registered as an observer.

Thread : Fatal Exception: NSRangeException
0  CoreFoundation                 0x000000018449259c __exceptionPreprocess + 132
1  libobjc.A.dylib                0x0000000194be40e4 objc_exception_throw + 60
2  CoreFoundation                 0x00000001844924dc -[NSException initWithCoder:]
3  Foundation                     0x00000001852a7e9c -[NSObject(NSKeyValueObserverRegistration) _removeObserver:forProperty:] + 528
4  Foundation                     0x00000001852a7954 -[NSObject(NSKeyValueObserverRegistration) removeObserver:forKeyPath:] + 104
5  AVFoundation                   0x0000000182d21054 -[AVCaptureSession _removeConnection:] + 192
6  AVFoundation                   0x0000000182d206dc -[AVCaptureSession _removeVideoPreviewLayer:] + 120
7  AVFoundation                   0x0000000182d300f8 -[AVCaptureVideoPreviewLayer dealloc] + 92
Run Code Online (Sandbox Code Playgroud)

对于停止捕获会话,使用以下代码:所有会话操作都在后台队列中处理,因为 stopRunning 可能需要一些时间

deinit {
  if let session = self.captureSession {
     dispatch_async(self.cameraQueue, { () -> Void in
        session.beginConfiguration()
        let allInputs = session.inputs as! [AVCaptureInput]
        for input in allInputs {
           session.removeInput(input)
        }
        let allOutputs = session.outputs as! [AVCaptureOutput]
        for output in allOutputs {
           session.removeOutput(output)
        }
        session.commitConfiguration()
        session.stopRunning()
     })
  }
}
Run Code Online (Sandbox Code Playgroud)

有人见过这次车祸吗?

use*_*008 6

AVCaptureVideoPreviewLayer我也遇到了这个异常,为我解决的问题是在完成预览图层后(即在放弃对预览图层的引用之前)取消捕获会话。换句话说,在某些控制器中我有类似的东西:

previewLayer = AVCaptureVideoPreviewLayer(session: someSession)
Run Code Online (Sandbox Code Playgroud)

其中previewLayer是该控制器的一个属性,然后当我完成后previewLayer,在deinit控制器的 中我执行以下操作:

previewLayer.session = nil
Run Code Online (Sandbox Code Playgroud)

本来没有必要这样做,因为当预览层取消初始化时,它也会清空会话。但我在崩溃案例的堆栈跟踪中看到的情况是,预览层的 dealloc 没有像通常那样从所属控制器的 dealloc 调用,而是从NSKVODeallocate. 这意味着在所属控制器解除分配后,某些东西(KVO 相关?)必须一直保留在预览层上,并且仅在稍后释放它。(我不知道它是什么或是什么原因导致它。)也许存在一个错误,必须在捕获会话完成之前从预览层取消设置捕获会话,否则会崩溃(不应该,但它做)。这就是为什么我在完成会话后明确地自己取消设置会话。