Q:

Swift 4: Access Variables from DispatchQueue.main (Scope)

I have a CoreML Image Classification task, that takes the "live stream" from the iOS device's [video] camera and occurs in the background.  Once objects have been been identified, and other app logic has occurred, I would like to update the UI's label with some of the data. 
Can someone explain how the callout to DispatchQueue.main.asyc(execute: { }) is able to access the variable(s) I have been working with?  I think this is essentially a scoping issue? 
The code I am currently using:
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)
                }
            }
    }
}

Its the self.labelPrediction.text = "" lines inside the switch statement that is causing the issue.  This var is always 0 currently. 

A:

It's not the matter of DispatchQueue.  From processCameraBuffer(sampleBuffer:), your code update your UI before it get result. 
To solve this, you need to use escaping closure.  Your function should look like this. 
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)%"
    }
}

Scope of variable is not a problem from here.  You need to handle asynchronous task.  

Capture occurs. 
processCameraBuffer is called and VNCoreMLRequest executed. 
You will get data and execute processCameraBuffer's completion block, by completion(). 
Update Label.