Swift 4:从 DispatchQueue.main(范围)访问变量
Posted
技术标签:
【中文标题】Swift 4:从 DispatchQueue.main(范围)访问变量【英文标题】:Swift 4: Access Variables from DispatchQueue.main (Scope) 【发布时间】:2017-12-07 13:09:29 【问题描述】:我有一个 CoreML 图像分类任务,它从 ios 设备的 [视频] 摄像头获取“实时流”并在后台发生。一旦确定了对象,并且发生了其他应用程序逻辑,我想用一些数据更新 UI 的标签。
有人可以解释对DispatchQueue.main.asyc(execute: )
的标注如何能够访问我一直在使用的变量吗?我认为这本质上是一个范围界定问题?
我目前使用的代码:
func captureOutput(_ output: AVCaptureOutput, didOutput sampleBuffer: CMSampleBuffer, from connection: AVCaptureConnection)
processCameraBuffer(sampleBuffer: sampleBuffer)
func processCameraBuffer(sampleBuffer: CMSampleBuffer)
let coreMLModel = Inceptionv3()
if let model = try? VNCoreMLModel(for: coreMLModel.model)
let request = VNCoreMLRequest(model: model, completionHandler: (request, error) in
if let results = request.results as? [VNClassificationObservation]
var counter = 0
var otherVar = 0
for item in results[0...9]
if item.identifier.contains("something")
print("some app logic goes on here")
otherVar += 10 - counter
counter += 1
switch otherVar
case _ where otherVar >= 10:
DispatchQueue.main.async(execute:
let displayVarFormatted = String(format: "%.2f", otherVar / 65 * 100)
self.labelPrediction.text = "\(counter): \(displayVarFormatted)%"
)
default:
DispatchQueue.main.async(execute:
self.labelPrediction.text = "No result!"
)
)
if let pixelBuffer: CVPixelBuffer = CMSampleBufferGetImageBuffer(sampleBuffer)
let handler = VNImageRequestHandler(cvPixelBuffer: pixelBuffer, options: [:])
do
try handler.perform([request])
catch
print(error.localizedDescription)
导致问题的 switch 语句中的 self.labelPrediction.text = ""
行。此 var 当前始终为 0。
【问题讨论】:
尝试在您提到的行上放置一个断点,看看变量包含什么。 (通常,块捕获它们需要的值。) 【参考方案1】:这不是DispatchQueue
的问题。从processCameraBuffer(sampleBuffer:)
,您的代码会在获得结果之前更新您的 UI。
要解决这个问题,您需要使用escaping closure
。您的函数应该如下所示。
func processCameraBuffer(sampleBuffer: CMSampleBuffer, completion: @escaping (Int, String) -> Void)
// 2.
let request = VNCoreMLRequest(model: model, completionHandler: (request, error) in
DispatchQueue.main.async(execute:
// 3.
let displayVarFormatted = String(format: "%.2f", otherVar / 65 * 100)
completion(counter, displayVarFormatted)
)
func captureOutput(_ output: AVCaptureOutput, didOutput sampleBuffer: CMSampleBuffer, from connection: AVCaptureConnection)
// 1.
processCameraBuffer(sampleBuffer) counter, displayVarFormatted in
/*
This Closure will be executed from
completion(counter, displayVarFormatted)
*/
// 4.
self.labelPrediction.text = "\(counter): \(displayVarFormatted)%"
变量的范围从这里不是问题。您需要处理异步任务。
-
捕获发生。
processCameraBuffer 被调用,
VNCoreMLRequest
被执行。
您将获取数据并执行processCameraBuffer
的完成块,由completion()
执行。
更新标签。
【讨论】:
谢谢@changnam-hong。此函数从 iOS 设备摄像头的“实时流”中调用: func captureOutput(_ output: AVCaptureOutput, didOutput sampleBuffer: CMSampleBuffer, from connection: AVCaptureConnection) processCameraBuffer(sampleBuffer: sampleBuffer) 所以这在每帧捕获时执行.它需要不断地重新扫描视频流,以便不断地进行图像分类。这会改变答案吗? 我已经实现了我的代码以遵循这种格式。但是,在第 4 步 XCode 仍然抱怨self.labelPrediction.text = ""
行仍然需要在主线程上运行。当我将它改回 DispatchQueue.main.async
时,这个变量再一次永远不会设置(或设置为 0)。以上是关于Swift 4:从 DispatchQueue.main(范围)访问变量的主要内容,如果未能解决你的问题,请参考以下文章
swift 使用Swift 4从用户设备访问相机,照片库,视频和文件
无法转换任何类型?要键入 AnyObject?从 swift 3 转换为 swift 4 时
如何在 Xcode 中将 Swift 版本从 5 更改为 4?