【问题标题】:Sending multiple instances of NSData with 'CBPeripheralManager' fails after first send首次发送后使用“CBPeripheralManager”发送多个 NSData 实例失败
【发布时间】:2014-10-24 09:08:21
【问题描述】:

所以我设置了这个代码:

for (int index = 0; index < [dataArray count]; index++) {
    dataToSend = [dataArray objectAtIndex:index];

    BOOL sent = [self.manager updateValue:dataToSend
                      forCharacteristic:(CBMutableCharacteristic *)self.cashierCarachteristic
                   onSubscribedCentrals:nil];

    if (!sent) {
        NSLog(@"Failed to send :(");
    }
}

然而,我的问题是,在发送数组中的第一块 NSData 之后,所有后续发送都失败了。我总是这样:

2014-10-24 17:01:45.162 Pengoo[1957:60b] 发送数据:94

2014-10-24 17:01:45.164 Pengoo[1957:60b] 发送数据:94

2014-10-24 17:01:45.166 Pengoo[1957:60b] 发送失败:(

2014-10-24 17:01:45.167 Pengoo[1957:60b] 发送数据:94

2014-10-24 17:01:45.168 Pengoo[1957:60b] 发送失败:(

2014-10-24 17:01:45.169 Pengoo[1957:60b] 发送数据:94

2014-10-24 17:01:45.170 Pengoo[1957:60b] 发送失败:(

谁能告诉我这是为什么?我是否可能错误地设置了我的经理,或者这是 CBPeripheralManager 或...的限制吗?

提前谢谢大家:)

【问题讨论】:

    标签: ios objective-c xcode bluetooth xcode6


    【解决方案1】:

    参考CBPeripheralManager documentation-

    讨论 您使用此方法发送特征的更新 价值——通过通知或指示——对选定的中心 订阅了该特征的值。

    如果方法返回 否,因为底层传输队列已满,外围设备 经理调用 peripheralManagerIsReadyToUpdateSubscribers: 方法 当传输队列中的更多空间变为 可用的。调用此委托方法后,您可以重新发送 更新。

    基本上,蓝牙硬件以有限的速率传输并具有有限的输入缓冲区,与设备的执行速度相比,这两者都相对较小 - 因此您的应用程序可能会比硬件快速生成更多的数据过程。

    updateValue 返回NO 时,您需要将传输请求排队并重新开始传输,直到调用peripheralManagerIsReadyToUpdateSubscribers: 委托方法之后。然后您可以继续传输,直到它再次返回 false

    【讨论】:

    • 糟糕!我的错。我略过那部分,认为没有必要。感谢陌生人的帮助!下次我一定会更彻底地阅读文档:)
    • @Paulw11,我可以在一个屏幕上有多个CBPeripheralManager 来广播2 个不同的信标吗?现在这种情况似乎并不奏效。任何建议将不胜感激。
    • 嗨。也许你应该问一个更详细的新问题;从您的评论中不清楚您要做什么。多个 CBPeripheral 管理器不会改变整体 BLE 吞吐量;这是硬件/无线电限制。
    【解决方案2】:

    我已经在我的一个应用程序中用一个简单的队列实现了它。

    @property (nonatomic, retain) NSMutableArray* queue;
    

    ...

    - (void) updateAllCharacteristics {
        @synchronized(self.queue)
            if (self.queue == nil) {
                self.queue = [NSMutableArray new];
            }
        }
        for (CBMutableCharacteristic* characteristic in self.service.characteristics) {
            NSString* newCharacteristicValue = [self getNewValueForCharacteristic:characteristic];;
            @synchronized(self.queue) {
                [self.queue addObject:@{ @"characteristic": characteristic, @"value": newCharacteristicValue }];
            }
        }
        [self processCharacteristicsUpdateQueue];
    }
    
    - (BOOL)updateCharacteristic:(CBMutableCharacteristic*)characteristic withValue:(NSString*) value {
        NSData* data = [value dataUsingEncoding:NSUTF8StringEncoding];
        return [self.peripheralManager updateValue:data forCharacteristic:characteristic onSubscribedCentrals:nil];
    }
    
    - (void)processCharacteristicsUpdateQueue {
        NSDictionary* characteristicData = [self.queue firstObject];
        if (characteristicData != nil) {
            while ([self updateCharacteristic:characteristicData[@"characteristic"] withValue:characteristicData[@"value"]]) {
                @synchronized(self.queue) {
                    [self.queue removeObjectAtIndex:0];
                }
                characteristicData = [self.queue firstObject];
                if (characteristicData == nil) {
                    break;
                }
            }
        }
    }
    
    - (void)peripheralManagerIsReadyToUpdateSubscribers:(CBPeripheralManager *)peripheral {
        [self processCharacteristicsUpdateQueue];
    }
    

    现在您必须修改代码以使其适应您的应用并调用 updateAllCharacteristics 方法。

    注意:请务必将 peripheralManager 的委托设置为您将其放入的此类

    【讨论】:

      【解决方案3】:

      斯威夫特 4.0

      Erhard Dinhobl 的回答

      struct SendingDataInfo {
          var characterist: CBCharacteristic
          var data: Data
          var centrals: [CBCentral]?
      }
      
      var sendingDataInfos = [SendingDataInfo]()
      let lockQueue = DispatchQueue(label: "com.test.LockQueue")
      
      var theCBPeripheralManager = CBPeripheralManager(delegate: self, queue: nil)
      
      func updateAllCharacteristics() {
          let fakeData = [SendingDataInfo]()  // Change to your data
          for sendingDataInfo in fakeData {
              lockQueue.sync() {
                  let temp = SendingDataInfo(characterist: sendingDataInfo.characterist, data: sendingDataInfo.data, centrals: sendingDataInfo.centrals)
                  sendingDataInfos.append(temp)
              }
          }
          processCharacteristicsUpdateQueue()
      }
      
      func updateCharacteristic(_ characteristicData: SendingDataInfo) -> Bool {
          return theCBPeripheralManager.updateValue(characteristicData.data, for: characteristicData.characterist as! CBMutableCharacteristic, onSubscribedCentrals: characteristicData.centrals)
      }
      
      func processCharacteristicsUpdateQueue() {
          guard let characteristicData = sendingDataInfos.first else {
              return
          }
          while updateCharacteristic(characteristicData) {
              lockQueue.sync() {
                  _ = sendingDataInfos.remove(at: 0)
                  if sendingDataInfos.first == nil {
                      return
                  }
              }
          }
      }
      
      func peripheralManagerIsReady(toUpdateSubscribers peripheral: CBPeripheralManager) {
          processCharacteristicsUpdateQueue()
      }
      

      现在您必须修改代码以使其适应您的应用并调用 updateAllCharacteristics 方法。

      注意:确保将 peripheralManager 的委托设置为您将其放入的此类

      【讨论】:

        猜你喜欢
        • 2013-09-20
        • 2017-07-05
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-05-09
        相关资源
        最近更新 更多