[英]Swift. How to get value of variable outside the function
我正在從事機器人項目,並嘗試獲取跟蹤對象的位置作為yTrack變量的值(請參見代碼)。 我可以從func handleVisionRequestUpdate打印yTrack,但是我需要在此功能之外訪問yTrack才能與其他功能一起使用。 以getCoord()為例。 請幫忙!
import AVFoundation
import Vision
import UIKit
import Foundation
class ViewController: UIViewController, AVCaptureVideoDataOutputSampleBufferDelegate {
var protocolString: String?
var inputStream: InputStream?
var outputStream: OutputStream?
var dataAsString: String?
var yTrack: Double?
@IBOutlet private weak var cameraView: UIView?
@IBOutlet private weak var highlightView: UIView? {
didSet {
self.highlightView?.layer.borderColor = UIColor.red.cgColor
self.highlightView?.layer.borderWidth = 4
self.highlightView?.backgroundColor = .clear
}
}
private let visionSequenceHandler = VNSequenceRequestHandler()
private lazy var cameraLayer: AVCaptureVideoPreviewLayer = AVCaptureVideoPreviewLayer(session: self.captureSession)
private lazy var captureSession: AVCaptureSession = {
let session = AVCaptureSession()
session.sessionPreset = AVCaptureSession.Preset.photo
guard
let backCamera = AVCaptureDevice.default(.builtInWideAngleCamera, for: .video, position: .back),
let input = try? AVCaptureDeviceInput(device: backCamera)
else { return session }
session.addInput(input)
return session
}()
override func viewDidLoad() {
super.viewDidLoad()
self.highlightView?.frame = .zero
self.cameraView?.layer.addSublayer(self.cameraLayer)
let videoOutput = AVCaptureVideoDataOutput()
videoOutput.setSampleBufferDelegate(self, queue: DispatchQueue(label: "MyQueue"))
self.captureSession.addOutput(videoOutput)
self.captureSession.startRunning()
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
self.cameraLayer.frame = self.cameraView?.bounds ?? .zero
}
public var lastObservation: VNDetectedObjectObservation?
func captureOutput(_ output: AVCaptureOutput, didOutput sampleBuffer: CMSampleBuffer, from connection: AVCaptureConnection) {
guard
let pixelBuffer: CVPixelBuffer = CMSampleBufferGetImageBuffer(sampleBuffer),
let lastObservation = self.lastObservation
else { return }
let request = VNTrackObjectRequest(detectedObjectObservation: lastObservation, completionHandler: self.handleVisionRequestUpdate)
request.trackingLevel = .fast
do {
try self.visionSequenceHandler.perform([request], on: pixelBuffer)
} catch {
print("Throws: \(error)")
}
}
public func handleVisionRequestUpdate(_ request: VNRequest, error: Error?) {
test {(yTrack) in
DispatchQueue.main.async {
guard let newObservation = request.results?.first as? VNDetectedObjectObservation else { return }
self.lastObservation = newObservation
guard newObservation.confidence >= 0.3 else {
self.highlightView?.frame = .zero
return
}
self.transformedRect = newObservation.boundingBox
self.transformedRect!.origin.y = 1 - self.transformedRect!.origin.y
let convertedRect = self.cameraLayer.layerRectConverted(fromMetadataOutputRect: self.transformedRect!)
self.highlightView?.frame = convertedRect
}
}
let yTrack = Double(self.transformedRect?.origin.y ?? 0.5)
// HERE IT WORKS, yTrack IS PRINTING, BUT I NEED IT OUTSIDE THIS FUNCTION
print(yTrack as Any)
}
public func test (returnCompletion: @escaping (AnyObject) -> () ){
DispatchQueue.global(qos: .background).async {
self.yTrack = Double(self.transformedRect?.origin.y ?? 0.5)
returnCompletion(self.yTrack as AnyObject)
}
}
public func getCoord () {
//HERE IT DOESN'T WORK. NOTHING IS PRINTING FROM HERE.
print(yTrack)
}
問題出在您的handleVisionRequestUpdate
函數上。
首先@Azat在注釋中是正確的:當您聲明let yTrack = Double(self.transformedRect?.origin.y ?? 0.5)
您將在此函數范圍內創建新變量,該變量與ViewController
的var yTrack
沒有關系范圍。
因此,當您在此函數中打印yTrack
,您將打印函數的內部變量,該變量將在函數返回后銷毀。 為了能夠在yTrack
外部使用yTrack
,您需要為ViewController
的youTrack
分配新值,然后就可以在想要的任何函數中使用它
yTrack = Double(self.transformedRect?.origin.y ?? 0.5)
第二個問題是DispatchQueue.main.async
。 在大多數情況下,將在此塊之后執行此塊中的代碼
let yTrack = Double(self.transformedRect?.origin.y ?? 0.5)
print(yTrack as Any)
那是因為使用此塊,您告訴編譯器“為此代碼塊創建單獨的«queue»,並在可以執行時異步執行它”,因此這一行self.transformedRect = newObservation.boundingBox
將在大多數情況下在此行let yTrack = Double(self.transformedRect?.origin.y ?? 0.5)
,您將在此行中擁有以前的transformedRect
,如果我理解正確的話,它將為nil
。 因此,從此函數中刪除DispatchQueue.main.async
或將self.yTrack = Double(self.transformedRect?.origin.y ?? 0.5)
移入其中。
查看下面的代碼。 我添加了很多評論,但沒有進行測試。 但是它應該解決問題。 發生了一些令人困惑的事情。 特別具有“測試”功能。 另外,您可能想練習使用self.myVar或self.myFunc(),以便開始更好地了解哪些變量是局部變量,哪些是視圖控制器上的屬性:
public func handleVisionRequestUpdate(_ request: VNRequest, error: Error?) {
// test {(yTrack) in /// remove this since we removed it below
DispatchQueue.main.async {
guard let newObservation = request.results?.first as? VNDetectedObjectObservation else { return }
self.lastObservation = newObservation
guard newObservation.confidence >= 0.3 else {
self.highlightView?.frame = .zero
return
}
self.transformedRect = newObservation.boundingBox
self.transformedRect!.origin.y = 1 - self.transformedRect!.origin.y
let convertedRect = self.cameraLayer.layerRectConverted(fromMetadataOutputRect: self.transformedRect!)
self.highlightView?.frame = convertedRect
//
// Move these into the Dispatch closure
// let yTrack = Double(self.transformedRect?.origin.y ?? 0.5) // delete this one
yTrack = Double(self.transformedRect?.origin.y ?? 0.5) // replace it with this one
print(yTrack as Any)
}
}
//
// Remove this. I'm not sure what it does, but its making things more complex
//
// public func test (returnCompletion: @escaping (AnyObject) -> () ){
// DispatchQueue.global(qos: .background).async {
// self.yTrack = Double(self.transformedRect?.origin.y ?? 0.5)
// returnCompletion(self.yTrack as AnyObject)
// }
// }
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.