2017-12-07 19 views
0

iOSデバイスの[ビデオ]カメラから「ライブストリーム」を取得し、バックグラウンドで発生するCoreMLイメージ分類タスクがあります。オブジェクトが特定され、他のアプリケーションロジックが発生したら、UIのラベルをいくつかのデータで更新したいと思います。Swift 4:DispatchQueue.main(範囲)のアクセス変数

DispatchQueue.main.asyc(execute: { })へのコールアウトが、私が作業していた変数にどのようにアクセスできるか説明できますか?私はこれが本質的にスコープの問題だと思いますか?

コード私は現在使用しています:問題の原因となっているswitch文の内側

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 = ""ライン。この変数は現在常に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. データを取得し、completion()によってprocessCameraBufferの完了ブロックを実行します。
  4. ラベルを更新します。
+0

ありがとう@ changnam-hong。この機能は、iOSデバイスのカメラからの "ライブストリーム" から呼び出される: FUNC captureOutput(_出力:AVCaptureOutput、didOutput sampleBuffer:CMSampleBuffer、接続から:AVCaptureConnection){ processCameraBuffer(sampleBuffer:sampleBuffer) } これはフレームキャプチャごとに実行されます。また、画像の分類が継続的に行われるように、ビデオストリームを継続的に再スキャンする必要があります。 これは答えを変えますか? –

+0

私はこのフォーマットに従うように自分のコードを実装しました。しかし、ステップ4では、 'self.labelPrediction.text =" "'という行がまだメインスレッド上で実行されている必要があるとXCodeは依然として不平を言っています。 これを 'DispatchQueue.main.async {}'に変更すると、この変数は決して設定されません(または0に設定されます)。 –