我正在尝试使用AVCaptureVideoPreviewLayer捕获视频,但是,当我运行我的应用程序时,主线程检查器会导致崩溃。
必须在什么时候在主线程上运行代码-我假设这将解决我遇到的问题。使用DispatchQueue.main.async({})
进行了几次尝试,但均无济于事。
发生错误:
主线程检查器:在后台线程上调用的UI API:
原文:
var videoPreviewLayer: AVCaptureVideoPreviewLayer {
let previewlayer = layer as! AVCaptureVideoPreviewLayer
switch gravity {
case .resize:
previewlayer.videoGravity = AVLayerVideoGravity.resize
case .resizeAspect:
previewlayer.videoGravity = AVLayerVideoGravity.resizeAspect
case .resizeAspectFill:
previewlayer.videoGravity = AVLayerVideoGravity.resizeAspectFill
}
return previewlayer
}
尝试修复:
var videoPreviewLayer: AVCaptureVideoPreviewLayer {
getVideoPreviewLayer { (previewLayer) in
return previewLayer
}
}
func getVideoPreviewLayer( completion: @escaping (AVCaptureVideoPreviewLayer) -> ()) {
DispatchQueue.main.async { [unowned self ] in
let previewlayer = self.layer as! AVCaptureVideoPreviewLayer
switch self.gravity {
case .resize:
previewlayer.videoGravity = AVLayerVideoGravity.resize
case .resizeAspect:
previewlayer.videoGravity = AVLayerVideoGravity.resizeAspect
case .resizeAspectFill:
previewlayer.videoGravity = AVLayerVideoGravity.resizeAspectFill
}
completion(previewlayer)
}
}
答案 0 :(得分:1)
这是一种解决方案,可确保无论使用哪个队列访问videoPreviewLayer
,您都只能在主队列上获得该层:
var videoPreviewLayer: AVCaptureVideoPreviewLayer {
let previewlayer: AVCaptureVideoPreviewLayer = {
if Thread.current.isMainThread {
return layer as! AVCaptureVideoPreviewLayer
} else {
DispatchQueue.main.sync {
return layer as! AVCaptureVideoPreviewLayer
}
}
}()
switch gravity {
case .resize:
previewlayer.videoGravity = AVLayerVideoGravity.resize
case .resizeAspect:
previewlayer.videoGravity = AVLayerVideoGravity.resizeAspect
case .resizeAspectFill:
previewlayer.videoGravity = AVLayerVideoGravity.resizeAspectFill
}
return previewlayer
}
答案 1 :(得分:0)
如错误消息中所述,您尝试的修复程序将无法编译,因为它期望返回值,同时您将此getter包装在异步调度中。
这里的重点不是如何定义吸气剂,而是如何使用它。只要您记得这是与UI相关的API,并且只需要从主线程调用它,代码的原始部分就可以了。因此,与其将代码的这一部分弄乱,不如将对videoPreviewLayer
的调用包装在DispatchQueue.main.async
调用中,如下所示:
DispatchQueue.main.async {
let _ = _something_.videoPreviewLayer
}
答案 2 :(得分:0)
您应该使用DispatchQueue.main.sync
,因为您要等待响应(您要返回结果值)。使用异步会导致您的代码在获得值之前继续执行。
您也不需要处理单独的功能。
这是一个应该起作用的简单修复程序:
var videoPreviewLayer: AVCaptureVideoPreviewLayer {
let capturedLayer = DispatchQueue.main.sync {
previewlayer = layer as! AVCaptureVideoPreviewLayer
switch gravity {
case .resize:
previewlayer.videoGravity = AVLayerVideoGravity.resize
case .resizeAspect:
previewlayer.videoGravity = AVLayerVideoGravity.resizeAspect
case .resizeAspectFill:
previewlayer.videoGravity = AVLayerVideoGravity.resizeAspectFill
}
return previewlayer
}
return capturedLayer
}
但是,尝试使用此函数返回的图层可能会遇到问题,因为您将离开主线程。最好将DispatchQueue.main.sync
移至其他地方的主线程(在上下文中获得videoPreviewLayer变量的某个地方)。