2017-09-28 83 views
0

我遇到问题了解或使用Dispatchgroup。我已经阅读了很多关于它们的内容,但是大多数示例/文档都非常模糊,或者与我想要做的不一样,但是每次我提到我的问题时,大家都会说“使用派送组”。DispatchGroup.wait不等待

这里就是我想要做的(注:顺序是至关重要的):

  • 发送蓝牙写入特性。
  • 设备接收值,并吐出的东西响应
  • 读取蓝牙响应(通过读特性)
  • 发送一条新的写入特性(不同的命令)
  • 设备接收到新的命令,吐出NEW数据响应

重复两次(总共3个命令,总共3个不同的响应)。


我的代码:

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

这就要求它有下面的代码并确认蓝牙写命令:

func peripheral(_ peripheral: CBPeripheral, didWriteValueFor descriptor: CBDescriptor, error: Error?) { 
     guard error == nil else { 
      print("Error writing descriptor: " + (error?.localizedDescription)!) 
      return 
     } 
     print("Descriptor Value 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 

现在,和你一样可以看到“特征值发送”是蓝牙功能在发送值时给出的确认,但是这个输出是在它完成运行整个代码之后创建的,所以基本上它把这些命令放在一些管道中,忘记了它们做了其他事情,那么发送的命令,因此我读的回应都是废话!正如你可以看到所有收到的字符串都是T-Pod-9Ch(这只是它的正常脉冲输出),我应该从命令中得到的预期响应是OK,OK和一个6位数字(按此顺序)。
请大家帮忙,我已经读了很多次关于派遣组应该如何工作,但我不能让他们做我想做的事情。

+1

你进入,离开,和在一个单独的线程上等待组。这完全没有意义。每次你调用wait(),因为你已经离开了组,所以组的计数器是'0'。 –

+0

你能详细说明一下吗?我真的不知道它应该如何格式化,然后从我所了解的每个单独的任务必须在enter/leave命令中,我需要它们等待它完成每个单独的命令。 –

+0

调度队列用于在线程。通常你可以这样使用它们:1)在当前线程上调用'enter()',2)启动一些异步任务和/或在另一个线程或调度队列上运行一些代码。3)让async任务调用'leave()当完成时,4)重复执行任何其他需要完成的任务,并且5)当所有的'enter()'调用通过'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

  4. 还有一种方法得到的答案命令2 后陆续方法...

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

我会尽量使用这个,它似乎做我想要的。我只是有一个简单的问题,程序如何知道回调是什么?就像说我有一个方法调用外设的didwritevaluefor(参见我的原始代码)。程序如何知道它必须等到它收到“确认”(或我有的打印语句)。我在想如果我在那里发布通知。 。 .just以便我可以确保等到它在写入之前写入它 –

+0

@ dvd.Void回调函数只是一个没有任何参数并且不返回任何对象的函数。您只需调用它离开调度组并开始下一个方法调用。如果没有人会调用answerReceived()方法,那么该应用程序将不会离开该组,并且安装过程将不会完成。每个sendCommand调用都会改变存储的回调以在完全命令后离开组。你可以使用通知,委托或其他。在确定执行了该命令时,您应该在发送每个命令之后调用answerReceived()。 – Woof

+0

@ dvd.Void哦,等等,在你的情况下,似乎你必须存储所有的块......我不确定,但如果你获得一个异步的命令写入结果,所以它可能会改变第二个函数存储的回调,在第一个使用该回调之前。我们需要测试它并检查控制台输出的方式与您在问题中显示的方式相同。如果回调函数的顺序不成立,那么我们将不得不为每个命令使用DispatchWorkItem将它们存储在块数组中,或者使用DispatchSemaphore。但无论如何,让我知道它将如何在你的代码中工作。稍后我们也可能会进行聊天,以使代码生效。 – Woof