迅速。如何在函数外获取变量的值

时间:2018-10-17 05:36:00

标签: swift function variables

我正在从事机器人项目,并尝试获取跟踪对象的位置作为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)
}

2 个答案:

答案 0 :(得分:0)

问题出在您的handleVisionRequestUpdate函数上。

首先@Azat在注释中是正确的:声明let yTrack = Double(self.transformedRect?.origin.y ?? 0.5)时,将在此函数的范围内创建新变量,该变量与var yTrack范围内的ViewController没有任何关系。

因此,当您在此函数中打印yTrack时,将打印函数的内部变量,该内部变量将在函数返回后销毁。为了能够在功能之外使用yTrack,您需要为ViewController的{​​{1}}分配新值,然后就可以在所需的任何功能中使用它了

youTrack

第二个问题是yTrack = Double(self.transformedRect?.origin.y ?? 0.5) 。在大多数情况下,将在此块之后执行该块中的代码

DispatchQueue.main.async

那是因为使用此块,您告诉编译器“为此代码块创建单独的«queue»,并在可能时异步执行”,因此在大多数情况下,此行let yTrack = Double(self.transformedRect?.origin.y ?? 0.5) print(yTrack as Any) 将完成在此行self.transformedRect = newObservation.boundingBox之后,您将在此行中有上一个let yTrack = Double(self.transformedRect?.origin.y ?? 0.5),如果我理解正确的话,您将在transformedRect内。因此,请从此功能中删除nil或将DispatchQueue.main.async移入该功能。

答案 1 :(得分:0)

查看以下代码。我添加了很多评论,但没有进行测试。但是它应该解决问题。发生了一些令人困惑的事情。特别具有“测试”功能。另外,您可能想练习使用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)
//     }
// }