簡體   English   中英

迅速。 如何在函數外獲取變量的值

[英]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)您將在此函數范圍內創建新變量,該變量與ViewControllervar yTrack沒有關系范圍。

因此,當您在此函數中打印yTrack ,您將打印函數的內部變量,該變量將在函數返回后銷毀。 為了能夠在yTrack外部使用yTrack ,您需要為ViewControlleryouTrack分配新值,然后就可以在想要的任何函數中使用它

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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM