Ios 添加AVCaptureDeviceInput时AVCaptureSession崩溃
我在Crashlytics上看到了一个奇怪的崩溃,当时我正在设置一个摄像头会话。 stacktrace显示崩溃发生在方法addInputIos 添加AVCaptureDeviceInput时AVCaptureSession崩溃,ios,swift,avfoundation,avcapturesession,Ios,Swift,Avfoundation,Avcapturesession,我在Crashlytics上看到了一个奇怪的崩溃,当时我正在设置一个摄像头会话。 stacktrace显示崩溃发生在方法addInput func setupCamSession(){ self.captureSession = AVCaptureSession() self.cameraView.setSession(self.captureSession) self.sessionQueue = dispatch_queue_create("com.myapp.cam
func setupCamSession(){
self.captureSession = AVCaptureSession()
self.cameraView.setSession(self.captureSession)
self.sessionQueue = dispatch_queue_create("com.myapp.camera_queue", DISPATCH_QUEUE_SERIAL)
self.setupResult = .Success
switch AVCaptureDevice.authorizationStatusForMediaType(AVMediaTypeVideo){
case .Authorized:
break //already we set it to success
case .NotDetermined:
// The user has not yet been presented with the option to grant video access.
// We suspend the session queue to delay session setup until the access request has completed
dispatch_suspend(self.sessionQueue)
AVCaptureDevice.requestAccessForMediaType(AVMediaTypeVideo, completionHandler: { (granted) -> Void in
if ( !granted ) {
self.setupResult = .CameraNotAuthorized
}
dispatch_resume(self.sessionQueue)
})
default:
self.setupResult = .CameraNotAuthorized
}
dispatch_async(self.sessionQueue){
if self.setupResult != .Success{
return
}
//link input to captureSession
guard let videoDevice = self.deviceWithMediaType(AVMediaTypeVideo, position: AVCaptureDevicePosition.Back) else{
AppLog("Video Device Unavailable")
self.setupResult = .SessionConfigurationFailed
return
}
var videoDeviceInput: AVCaptureDeviceInput!
do {
videoDeviceInput = try AVCaptureDeviceInput(device: videoDevice)
}catch {
AppLog("Could not create video device input")
}
/////////////////////////////////////////////////////
self.captureSession.beginConfiguration()
if self.captureSession.canAddInput(videoDeviceInput){
self.captureSession.addInput(videoDeviceInput)
self.videoDeviceInput = videoDeviceInput
self.videoDevice = videoDevice
dispatch_async(dispatch_get_main_queue()){
//update the cameraView layer on the main thread
let previewLayer : AVCaptureVideoPreviewLayer = self.cameraView.layer as! AVCaptureVideoPreviewLayer
previewLayer.connection.videoOrientation = AVCaptureVideoOrientation(ui:UIApplication.sharedApplication().statusBarOrientation)
}
}else{
AppLog("Could not add video device input to the session")
self.setupResult = .SessionConfigurationFailed
}
//link output to captureSession
let stillImageOutput = AVCaptureStillImageOutput()
if self.captureSession.canAddOutput(stillImageOutput){
self.captureSession.addOutput(stillImageOutput)
self.stillImageOutput = stillImageOutput
stillImageOutput.outputSettings = [AVVideoCodecKey : AVVideoCodecJPEG]
}else{
AppLog("Could not add still image output to the session")
self.setupResult = .SessionConfigurationFailed
}
self.captureSession.commitConfiguration()
/////////////////////////////////////////////////////
}
}
func runSession(){
dispatch_async(self.sessionQueue){
switch self.setupResult!{
case .Success:
self.videoDeviceInput!.device.addObserver(self, forKeyPath: "adjustingFocus", options: NSKeyValueObservingOptions.New, context: nil)
self.captureSession.addObserver(self, forKeyPath: "running", options: [.New], context: &SessionRunningContext)
self.captureSession.startRunning()
self.captureSessionRunning = self.captureSession.running
if !self.captureSessionRunning {
self.captureSession.removeObserver(self, forKeyPath: "running", context: &SessionRunningContext)
self.videoDeviceInput?.device?.removeObserver(self, forKeyPath: "adjustingFocus", context: nil)
}
default:
//Handle errors.
}
}
func stopCaptureSession(){
dispatch_async(self.sessionQueue){
if self.setupResult == .Success{
if self.captureSessionRunning{
self.captureSession.stopRunning()
self.videoDeviceInput?.device?.removeObserver(self, forKeyPath: "adjustingFocus", context: nil)
self.captureSession.removeObserver(self, forKeyPath: "running", context: &SessionRunningContext)
}
self.captureSessionRunning = false
}
}
}
setupCamSession在viewDidLoad中调用,runSession在ViewWillDisplay中出现,我在ViewWillDemouse中还有一个stopSession方法。与摄像头会话相关的所有内容都在后台串行队列中调度
崩溃不会100%发生,我无法在我使用的设备上重现崩溃。
谢谢
确保您正在删除Denit上的观察者。我在返回摄像头捕获屏幕时看到了这种情况,我没有移除调整焦距的观测者。一旦我在Denit中删除了它,一切都很好 也有同样的问题。在Info.plist文件中添加了
隐私-摄像头使用说明
的使用说明后,问题得以解决。此答案包含有关如何设置描述的提示:
将其移动到ViewWillDisplay或ViewDidAppear为什么?我更喜欢将其保存在viewDidLoad()中。事实上,主屏幕上有摄像头视图,我们在主屏幕上多次按下和弹出视图控制器。因此,VIEWWILLISPEND将被多次调用,并且每次都将再次设置相机会话。目前,它只是在运行摄像头会话。我的灵感来自。他们在viewDidLoad()中设置输入崩溃报告中还有其他信息吗?就像“在参数寄存器中找到选择器名称”?不。这是我在报告中的全部内容。我编辑了我的问题并添加了stopCaptureSession()方法。此方法是移除用于调整焦点的观察者。日志上说观察员已经被移除,然后Denit被调用。是否有可能videoDeviceInput.device以某种方式变为零?如果发生这种情况,
self.videoDeviceInput?.device?.removeObserver(self,forKeyPath:“adjustingFocus”,context:nil)
将不会被调用。非常感谢。这正是我的问题。