2017-09-28 12 views
0

Dispatchgroupを理解している、または使用している問題があります。私はそれらについて多くを読んだことがありますが、ほとんどの例/ドキュメントは非常にあいまいであり、私がやりたいことに似ていませんが、私の問題を言及するたびに誰もが "DISPATCH GROUPSを使う"と言います。DispatchGroup.waitが待機していません

は、ここで私が何をしたいのです(注:順番は重要です):

  • は、Bluetoothの書き込み特性を送信します。
  • デバイスが値を受け取り、応答
  • 読むブルートゥース応答(読み取り特性を経由して)
  • で何かを吐くことは
  • デバイスは、NEWコマンドを受信NEWを吐く新しい書き込み特性(異なるコマンド)を送信しますデータ応答

2回繰り返す(合計3コマンド、合計3応答)。


マイコード:これは次のコードとの確認があるbluetoothの書き込みコマンドを呼び出します

func tPodInitialSetUp() 
    { 
     print ("* * * * * BEGIN SET-UP * * * * *") 
     let setupDispatchGroup = DispatchGroup() 

     setupDispatchGroup.enter() 
     self.writeValue(command: Data(CommandModeCmd)) //231: Put t-Pod in command mode, burst mode is OFF returns OK 
     setupDispatchGroup.leave() 

     setupDispatchGroup.wait() 

     setupDispatchGroup.enter() 
     deviceConnected?.readValue(for: deviceConnectedCh1n2Char!) 
     print("Sent command 231: returned: \(receivedString1)") 
     if receivedString1.lowercased() == "ok" 
     { 
      print("t-Pod burst mode is OFF") 
     } 
     setupDispatchGroup.leave() 

     setupDispatchGroup.wait() 

     setupDispatchGroup.enter() 
     self.writeValue(command: Data(loadProbeCalCmd)) //202: load calibration constants of probe, returns ok or 0 
     setupDispatchGroup.leave() 

     setupDispatchGroup.wait() 

     setupDispatchGroup.enter() 
     deviceConnected?.readValue(for: deviceConnectedCh1n2Char!) 
     print("Sent command 202: returned: \(receivedString1)") 
     if receivedString1.lowercased() == "ok" 
     { 
      print("Probe Constants loaded") 
     } 
     if receivedString1 == "0" 
     { 
      print("No probe connected") 
     } 
     setupDispatchGroup.leave() 

     setupDispatchGroup.wait() 

     setupDispatchGroup.enter() 
     self.writeValue(command: Data(probeSNCmd)) //205: load probe serial number 
     setupDispatchGroup.leave() 

     setupDispatchGroup.wait() 

     setupDispatchGroup.enter() 
     deviceConnected?.readValue(for: deviceConnectedCh1n2Char!) 
     print("Sent command 205: returned: \(receivedString1)") 
     if (receivedString1.count == 6) 
     { 
      print("received Probe SN: \(receivedString1)") 
      probeSN = receivedString1 
     } 
     setupDispatchGroup.leave() 

     setupDispatchGroup.notify(queue: .main) 
     { 
      tPodSN = String(describing: connectedDeviceName!.dropFirst(7)) 
      print ("* * * SET-UP COMPLETE * * *") 
      self.writeValue(command: Data(resetCmd)) //200: resets t-Pod 
      self.writeValue(command: Data(beaconOffCmd)) //211: turns beacon off (temperature output) 
     } 

     DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) 
     { 
      self.dataDisplaySubView.isHidden = false 
      print ("Adding observers!") 

      NotificationCenter.default.addObserver(self, selector: #selector(self.updateIncomingData), name: NSNotification.Name(rawValue: DATA_PARSED), object: nil) //Run every time you receive data from BLE 

      NotificationCenter.default.addObserver(self, selector: #selector(self.calculateTNU), name: NSNotification.Name(rawValue: TOGGLESWITCH_TOGGLED), object: nil) //Run in case the toggle switches change and data needs to be re-calculated 

      NotificationCenter.default.addObserver(self, selector: #selector(self.parseReceivedData), name: NSNotification.Name(rawValue: DEVICE_FINISHED_SENT_DATA), object: nil) //Run every time you receive the notification that the whole data has been sent 
     } 
    } 

* * * * * BEGIN SET-UP * * * * * 
***** WRITING ***** 
Wrote: 1 bytes 
***** WRITING ***** 
Wrote: 1 bytes 
Sent command 231: returned: **T-Pod-9Ch** 
***** WRITING ***** 
Wrote: 1 bytes 
Sent command 202: returned: **T-Pod-9Ch** 
***** WRITING ***** 
Wrote: 1 bytes 
Sent command 205: returned: **T-Pod-9Ch** 
* * * SET-UP COMPLETE * * * 
***** WRITING ***** 
Wrote: 1 bytes 
***** WRITING ***** 
Wrote: 1 bytes 
Characteristic Value sent 
Adding observers! 
Characteristic Value sent 
Characteristic Value sent 
Characteristic Value sent 
Characteristic Value sent 
Clearing TNU Array 
:今

func peripheral(_ peripheral: CBPeripheral, didWriteValueFor descriptor: CBDescriptor, error: Error?) { 
     guard error == nil else { 
      print("Error writing descriptor: " + (error?.localizedDescription)!) 
      return 
     } 
     print("Descriptor Value sent") 
    } 

は、ここに私の出力です

今、あなたのように"Characteristic Value Sent"は、Bluetoothの機能が値を送信したときの確認ですが、この出力はコード全体の実行が完了した後に作成されるため、基本的にはコマンドをパイプラインに入れ、それからコマンドを送ったので、私が読んでいる応答はすべてナンセンスです!受信した文字列はすべてT-Pod-9Ch(これは通常のバースト出力です)であり、コマンドから取得する必要がある応答はOK、OK、6桁の数字です(その順番)。
ディスパッチグループの仕事の仕方について何度も読んだことがありますが、私が望むことをすることができません。

+1

が必要な場合は、入力している知ってみましょう残し、かつグループ全体を1つのスレッドで待機します。それは全く無意味です。 'wait()'を呼び出すたびに、あなたはすでにグループから退いたので、グループのカウンタは '0'になります。 –

+0

あなたはそれについて詳述できますか?私は実際にそれがどのようにフォーマットされているのか理解できません。個々のタスクが入力/退出コマンド内になければならないと理解していました。そして、個々のコマンドを完了するのを待つ必要があります。 –

+0

ディスパッチキューは、スレッド。 1)現在のスレッドで 'enter()'を呼び出す、2)いくつかの非同期タスクを開始する、または別のスレッドまたはディスパッチキューでコードを実行する、3)非同期タスクコールにleave() 'done()'コールが 'leave()'によってバランスが取られているときに 'notify()'を使ってコードを実行させる必要があります。コール。 –

答えて

0

あなたの質問が正しい場合は、新しいコマンドを送信する前に回答を待つ必要があります。

あなたの書き込みには完了ブロックがありません。そのため、あなたのケースではdispatchGroupを使用するのは意味がありません。

以下のコードは、いくつかのオプションがあり、あなたの状況では

func someMethod(completionHandler: @escaping()-> Void) { 


//we need to get or set some data in separated queue 
    DispatchQueue.global(qos: .background).async { 

    let group = DispatchGroup() 

    //let's say we have an array of urls and we need to load images and put them to an array 
    for url in someUrlArray { 
      group.enter() 
      SomeLoaderClass.load(url) { image in 
       //add received image 

       //leave the group 
       group.leave() 
      } 
    } 

    //now we need to wait until all images will be downloaded 
    group.wait() 

    //then we can finish and call the completion in the main queue 
    DispatchQueue.main.async { 
     completionHandler() 
    } 
    } 
} 

をディスパッチグループを使用するための一般的な例である:あなたが一つのコマンドを送信し、応答を受信した場合ことがわかっている場合、

ファーストをコマンド1

を送信するための一つの方法

  1. コール:まさにそのコマンドのために、あなたは以下の順序でメソッドを呼び出すことができます

  2. コール命令1のための答えが

  3. コールコマンドをコマンド2 のための答えを取得した後、2

  4. そして、もう一つの方法を送信するためにさらに別の方法を受信されます後に別の方法...

n。設定を完了する

ユーザーを登録する必要があるように、定義済みの資格情報を最初に送信し、サーバーからトークンを取得し、その後に何かを実行する必要があります。

ですから、各コマンドの追加のメソッドを追加する必要があります、あなたはそのため認識できない場合は、ご注文

に従ってそれらを呼び出しますが、あなたが答えを取得するつもりだとあなたは必ずすることを命じます「あなたは以下のようにしてディスパッチグループを使用することができ、一つだけコマンドを送信し、唯一の答えを待っていまし:

typealias Callback =()->Void 
class SomeManagerClass { 
     var callback: Callback? 

     func initiateSetup(){ 
       DispatchQueue.global(qos: .background).async { [weak self] in 
        let group = DispatchGroup() 
        //now we can send commands 
        group.enter() 
        self?.sendCommand(SomeDataForTheFirstCommand) { 
          //when the first answer will be received, it will init the callback, so you can leave the group now 
         group.leave() 
        } 
        //sending the second command 
        group.enter() 
        self?.sendCommand(SomeDataForTheSecondCommand) { 
          //waiting for the second answer will be received 
         group.leave() 
        } 

        //.... more commands sending same way 
        group.wait() 
        //now all commands was send and you got an answer for each 

        //finishing setup 
         DispatchQueue.main.async{ 
         self?.finishSetup() 
        } 
       } 
     } 

     func sendCommand(_ command: Data, callback: Callback?){ 
      self.writeValue(command: command) 
      self.callback = callback 
     } 

     func answerReceived(){ 
      //this is just an example method that is called when you get an answer for any command 
      //now we can callback 
      self.callback?() 
     } 

     func finishSetup(){ 

      //do something 
     } 
} 

、私はあなたが詳細

+0

私はこれを使用しようとします、それは私が欲しいものをするようです。私はちょうど簡単な質問があります、プログラムはコールバックが何であるか知っていますか?私は、その周辺機器の書き込みのためのメソッドを持っていると言うように(私の元のコードを参照してください)。プログラムは、 "確認"(または私が持っている印刷ステートメント)を受け取るまで待たなければならないことをどのようにして知っていますか?もし私がそこに何か通知をすれば、私は考えていました。 。それだけを書く前にそれを書くまで待つようにしてください。 –

+0

@ dvd.Voidコールバックはパラメータを持たず、オブジェクトを返さない単なる関数です。ディスパッチグループを離れ、次のメソッド呼び出しを開始するために呼び出すだけです。誰もanswerReceived()メソッドを呼び出さない場合、アプリケーションはグループを離れることはなく、セットアッププロセスは終了しません。各sendCommandコールは、正確なコマンドの後にグループを離れるために、格納されたコールバックを変更します。通知、デリゲートなどを使用できます。そのコマンドが実行されたことを確信した時点で、各コマンドが送信された後に、answerReceived()を呼び出すだけでよいのです。 – Woof

+0

@ dvd.Voidああ、あなたの場合は、すべてのブロックを保存する必要があるようです...私は確信していませんが、コマンドを非同期的に書き込むと、2番目の関数最初のコールバックを使用する前に、そのコールバックを使用します。私たちはそれをテストし、あなたの質問に表示したのと同じようにコンソール出力をチェックする必要があります。コールバックの順序が間違っている場合は、各コマンドにDispatchWorkItemを使用してブロックの配列に格納するか、DispatchSemaphoreを使用する必要があります。しかし、とにかく、あなたのコードでどのように動作するか教えてください。また、後でチャットしてコードを作成することもあります。 – Woof

関連する問題