Swift.Как получить значение переменной вне функции - PullRequest
0 голосов
/ 17 октября 2018

Я работаю над проектом робототехники и пытаюсь определить положение объекта отслеживания в качестве значения переменной yTrack (см. Код).Я могу напечатать yTrack из func handleVisionRequestUpdate, но мне нужен доступ к 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 голосов
/ 24 октября 2018

Проверьте код ниже.Я добавил много комментариев, но я не проверял это.Но это должно все исправить.Было несколько запутанных вещей, происходящих.Конкретно с функцией «тест».Также вы можете попрактиковаться в использовании 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)
//     }
// }
0 голосов
/ 17 октября 2018

Проблема с вашей handleVisionRequestUpdate функцией.

Прежде всего @Azat был прав в комментариях: когда вы объявляете let yTrack = Double(self.transformedRect?.origin.y ?? 0.5), вы создаете новую переменную в области действия этой функции, которая не имеет отношения к var yTrack из области действия ViewController.

Поэтому, когда вы печатаете 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)

, потому что с помощью этого блока вы говорите компилятору «создать отдельную« очередь »для этого блока кода и выполнять ее асинхронно, когда вы будетебыть в состоянии сделать это ", так что эта строка 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) в нее.

...