2017-12-07 7 views
0

iOS 장치의 [비디오] 카메라에서 "라이브 스트림"을 가져 와서 백그라운드에서 발생하는 CoreML 이미지 분류 작업이 있습니다. 객체가 식별되고 다른 응용 프로그램 논리가 발생하면 일부 데이터로 UI 레이블을 업데이트하고 싶습니다.스위프트 4 : DispatchQueue.main (범위)의 액세스 변수

DispatchQueue.main.asyc(execute: { })에 대한 설명 선이 내가 사용하고있는 변수에 어떻게 액세스 할 수 있는지 설명 할 수 있습니까? 나는 이것이 본질적으로 범위 문제라고 생각한다.

코드 내가 현재 사용하고 있습니다 : 문제를 일으키는 스위치 문 내부

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) 
       } 
      } 
    } 
} 

그것 self.labelPrediction.text = "" 라인. 이 var는 항상 현재 0입니다.

+0

언급 한 줄에 중단 점을 넣고 변수가 무엇인지 확인하십시오. 일반적으로 블록은 필요한 값을 캡처합니다. –

답변

0

DispatchQueue의 문제가 아닙니다. processCameraBuffer(sampleBuffer:)에서 결과를 얻기 전에 코드가 UI를 업데이트합니다.

이 문제를 해결하려면 escaping closure을 사용해야합니다. 함수는 다음과 같아야합니다.

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)%" 
    } 
} 

변수의 범위는 여기에서 문제가되지 않습니다. 비동기 작업을 처리해야합니다.

  1. 캡쳐가 발생합니다.
  2. processCameraBuffer가 호출되고 VNCoreMLRequest이 실행되었습니다.
  3. 데이터를 가져와 에 의해 processCameraBuffer의 완료 블록을 실행합니다.
  4. 레이블을 업데이트하십시오.
+0

감사합니다. @ changnam-hong. 이 기능은 iOS 장비의 카메라에서 "라이브 스트림"에서 호출됩니다 FUNC의 captureOutput (_ 출력 : AVCaptureConnection : 연결에서 CMSampleBuffer : AVCaptureOutput, didOutput sampleBuffer) { processCameraBuffer (sampleBuffer : sampleBuffer) } 따라서 이것은 모든 프레임 캡처에서 실행됩니다. 또한 이미지 분류가 계속 발생하도록 비디오 스트림을 지속적으로 다시 스캔해야합니다. 그러면 대답이 변경됩니까? –

+0

이 형식을 따르도록 코드를 구현했습니다. 그러나 4 단계에서 Xcode는 여전히'self.labelPrediction.text = ""'줄이 여전히 메인 쓰레드에서 실행되어야한다고 불평하고있다. 이 변수를'DispatchQueue.main.async {}'로 변경하면 다시 한번이 변수는 설정되지 않습니다 (또는 0으로 설정 됨). –