iOS 11 CoreBluetooth:无法删除关键路径“委托”的观察者 CBPeripheral

Posted

技术标签:

【中文标题】iOS 11 CoreBluetooth:无法删除关键路径“委托”的观察者 CBPeripheral【英文标题】:iOS 11 CoreBluetooth: Cannot remove an observer CBPeripheral for the key path "delegate" 【发布时间】:2017-12-15 09:04:59 【问题描述】:

自从 ios 11 发布以来,我遇到了偶发但频繁的崩溃,其特征​​如下:

Cannot remove an observer <CBPeripheral 0x1c010ef10> for the key path "delegate" from <CBPeripheral 0x1c010ef10> because it is not registered as an observer.

这发生在扫描蓝牙设备、稍后连接到其中一个设备以及最终清理整个过程的情况下。所有这些任务都在非主调度队列中执行,以减轻主线程的压力(以获得更流畅的 UI 体验)。自 iOS 9 天以来,这段代码一直在运行而没有发生任何事故,直到 iOS 11 发布后才开始崩溃。

到目前为止,我在网上找到的关于此行为的唯一参考资料是 Estimote SDK 的 this 和 this 帖子。这些参考表明,在不同的调度队列中 CBCentralManager 的并行实例可能会发生一些事情,但是,官方Programming Guide 中没有说明关于此事的特别注意事项。此外,Apple 员工 成员对another CoreBluetooth 问题的回复指出:

一般来说,iOS 11 对没有正确引用 CB 对象的应用程序的宽容度会降低...

听起来不太令人鼓舞。我尝试使用 XCode 及其配套工具分析应用程序并寻找潜在的泄漏,但这也没有说明太多。

有没有其他人遇到过类似的问题?关于如何解决它的任何建议?关于下一步在哪里挖掘的想法?

【问题讨论】:

自 iOS 11 以来我遇到了同样的事情,并且不确定原因或如何解决它。它也非常难以重现。 在与 Apple 员工的私人交流中,他建议在同一个线程中处理所有 CBCentral 活动,因为回调和其他消息事件向对象发送信号。显然,如果生成的对象(例如 CBPeripheral)在其他线程中被处理和释放,则所提到的信号可能会引用已释放的对象,因此会崩溃。不过,目前还没有明确的结论。 经过反复试验,我个人也得出了相同的结论,但我不想在这里写,直到我确认它已解决。这条知识应该以更易于搜索的方式发布。似乎至少与扫描相关的所有内容,或者包括外围设备的快速保留和释放都应该在同一个线程中处理。谢谢您的确认!它真的应该在文档中。 那么,究竟有什么解决方案呢?有人可以正确回答这个问题吗?将不胜感激。谢谢! 【参考方案1】:

经过一段时间的测试,在我们的特殊情况下,解决方案包括将所有与蓝牙堆栈相关的工作转换到 mainQueue。这意味着所有相关的回调都存在于主线程范围内。

此解决方案需要格外小心在这些回调中执行的工作(UI 也在此处运行),但由于大多数 CoreBluetooth 操作默认情况下是异步的,这已被证明是可行的。此解决方法已在 iOS 11 中得到确认,到目前为止,iOS 12 中也未报告任何问题。

这里的要点是:处理 mainQueue 中绝对必要的位,然后在必要时将其余负载转移到其他地方。

【讨论】:

以上是关于iOS 11 CoreBluetooth:无法删除关键路径“委托”的观察者 CBPeripheral的主要内容,如果未能解决你的问题,请参考以下文章

iOS 和 CoreBluetooth 需要低能耗吗?

CoreBluetooth [警告] 未知错误:2

在 CoreBluetooth iOS 中计算 Tx 功率电平

iOS中的蓝牙 CoreBluetooth蓝牙系列

CoreBluetooth 和 MFi

CoreBluetooth:scanForPeripheralsWithServices 不使用服务数组