核心蓝牙:如何为多个特征(30-40)设计代码?

10

我搜索了一下,发现这可能是一个重复的问题:

同一设备的多个CBPeripheral

我的问题是:

我有多个服务,总共有30-40个特征(是的,我需要它们全部...)。 对于处理CoreBluetooth,我始终使用苹果示例代码(CoreBluetooth温度传感器)作为起点。

发现和服务/特征处理分成两个类,对于只有几个特征来说,这样做没问题。但在一个类中处理这么多特征,这不是我所理解的"良好的软件设计"

人们想到的第一个想法是为每个服务创建一个类。但不幸的是,CBPeripheral同时只能有一个CBPeripheralDelegate。这意味着我不能将其分成几个类。

我们不必讨论BLE是否是获得此数量数据的正确技术 - 不是。但有制造商使用BLE,所以他们不必烦恼MFi计划...

我还阅读了最终提供的CoreBluetooth编程指南,但它只描述了基本工作流程,没有关于正确设计的内容。

我正在寻找一种好的设计方法。您可能有任何建议、提示或示例代码链接吗? 非常感谢!

1个回答

9
将逻辑分解成几个自包含的类总是好的设计。你应该根据服务或其他类别来组织你的代码。即使外围设备只有一个委托,你也可以轻松实现调度程序模式,在其中注册各种服务实现和选择键(实际上是服务对象),并将调用分派到指定的服务处理程序。如果服务类实现了CPPeripheralDelegate协议,则这个设计将允许你在需要时分别测试/重用每个服务,并在代码中最小程度地进行更改。
在伪obj-c代码中,分派器外围设备委托如下:
// The ivar/property serving as the registry
NSMutableDictionary *registeredHandlers = [[NSMutableDictionary alloc] init];

- (void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error {
  // for each service create an instance of its handler class and
  // add them to the registered handlers
  for (CBService *service : peripheral.services) {
    if (!registeredHandlers[service]) { // don't reinitialize if not needed
      ExtendedCBPeripheralDelegate *serviceHandler = [self instantiateHandlerForService:service];
      [registeredHandlers setObject:serviceHandler forKey:service];
      [serviceHandler discoverCharacteristics]; // make this functionality self contained for the service
    }
  }
}

在服务或特征相关的回调中,应该实现分派。以下是一个例子:
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error {
  ExtendedCBPeripheralDelegate *serviceHandler = registeredHandlers[service];
  [serviceHandler peripheral:peripheral didDiscoverCharacteristicsForService:service error:error];
}

- (void)peripheral:(CBPeripheral *)peripheral didWriteValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error {
  ExtendedCBPeripheralDelegate *serviceHandler = registeredHandlers[characteristic.service];
  [serviceHandler peripheral:peripheral didWriteValueForCharacteristic:characteristic error:error];
}

如果中央管理器关闭电源,则最好的解决方案是放弃整个外围委托。不要费心重新初始化,而是计划处理。当然,如果需要,您可以通知服务处理程序即将销毁。


首先感谢您的详细解释。只是想确认我是否理解正确:委托对象仍然留在管理多个服务处理程序的类中。那么,您会将检索到的值存储在哪里?在每个服务处理程序中还是在管理类中?您会使用全局NSNotifications来通知视图控制器有关新检索到的值吗? - orschaef
是的,您可以修改原始委托以实现调度程序模式。您可以在任何地方存储引用,只需确保服务处理程序在需要时可以访问它们。请记住不要尝试缓存它们,Core Bluetooth会在可能的情况下为您执行此操作。使用通知是实现松散耦合的一种方法,但我更喜欢使用ReactiveCocoa中的信号。这是一个很棒的库!查看repo并阅读文档https://github.com/ReactiveCocoa/ReactiveCocoa 如果您有任何问题,请打开问题或在SO上发布。一旦您习惯了它,您会喜欢它的。 - allprog
这是一个非常棒的答案,感谢您抽出时间写下它。 - cbowns
2
一件小事:我记得当我使用NSNotifications传输这么多数据时,应用程序最终会冻结。通知风暴对于传输数据真的不是一个好主意...(虽然我很久以前做过这个,但我认为这对于任何iOS新手来说仍然是一个重要的信息)。 - orschaef

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接