You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

iOS同一APP中多CBCentralManager未调用状态更新函数问题

多个CBCentralManager实例仅第一个触发状态更新(iOS 16)

环境

  • iOS版本:16.1/16.2
  • Xcode版本:14.1

问题描述

初始化多个CBCentralManager实例时,仅第一个实例会调用代理的centralManagerDidUpdateState()方法更新状态,其余实例状态始终为unknown,不会触发状态更新回调。

期望结果

所有CBCentralManager实例都能调用各自代理的centralManagerDidUpdateState()方法。比如测试代码中的第二个管理器应打印SECOND MANAGER UPDATED STATE.。

背景

因引入第三方库需使用多个CBCentralManager,该库会自行初始化Core Bluetooth中心管理器。按库文档说明,相关对象应可在自定义centralManager代理的didDiscover方法内初始化,但实际运行异常,排查后确定问题出在多CBCentralManager的使用上。

目前临时方案是仅使用一个CBCentralManager实例传入该库,但需修改库源码,可能引发非官方兼容问题。该库文档显示2022年9月功能正常,不确定是Apple修改了Core Bluetooth行为限制多实例运行,还是开发环境存在问题。

复现代码

ModelData(初始化中心管理器)

import Foundation
import Combine
import CoreBluetooth

final class ModelData {
    let centralManager: CBCentralManager!
    let secondCentralManager: CBCentralManager!

    init() {
        let centralManagerDelegate = CentralManagerDelegate()
        centralManager = CBCentralManager(delegate: centralManagerDelegate, queue: nil)
        let secondCMDelegate = SecondCentralManagerDelegate()
        secondCentralManager = CBCentralManager(delegate: secondCMDelegate, queue: nil)
        print("initialized central managers")
    }
}

第一个中心管理器代理类

import Foundation
import CoreBluetooth

class CentralManagerDelegate: NSObject, ObservableObject, CBCentralManagerDelegate  {
    func centralManagerDidUpdateState(_ central: CBCentralManager) {
        switch central.state {
        case .unknown:
            print("Bluetooth Device is UNKNOWN")
        case .unsupported:
            print("Bluetooth Device is UNSUPPORTED")
        case .unauthorized:
            print("Bluetooth Device is UNAUTHORIZED")
        case .resetting:
            print("Bluetooth Device is RESETTING")
        case .poweredOff:
            print("Bluetooth Device is POWERED OFF")
        case .poweredOn:
            print("Bluetooth Device is POWERED ON")
        @unknown default:
            print("Unknown State")
        }
    }
}

第二个中心管理器代理类

import Foundation
import CoreBluetooth

class SecondCentralManagerDelegate: NSObject, ObservableObject, CBCentralManagerDelegate  {
    func centralManagerDidUpdateState(_ central: CBCentralManager) {
        print("SECOND MANAGER UPDATED STATE")
    }
}

调用ModelData的视图

struct HomeScreen: View {
    @StateObject private var modelData = ModelData()
    @State private var showDetail = true

    var body: some View {
    }
}

运行输出

initialized central managers
Bluetooth Device is POWERED ON

解决方案

1. 核心原因

CBCentralManager对代理的引用是弱引用,你代码中的代理对象是局部变量,初始化完成后无强引用持有者,被ARC提前释放,因此无法接收回调。

2. 修复代码

修改ModelData类,将代理对象保存为属性以保持强引用:

final class ModelData {
    let centralManager: CBCentralManager!
    let secondCentralManager: CBCentralManager!
    // 添加属性持有代理对象
    private let centralDelegate: CentralManagerDelegate
    private let secondCentralDelegate: SecondCentralManagerDelegate

    init() {
        centralDelegate = CentralManagerDelegate()
        centralManager = CBCentralManager(delegate: centralDelegate, queue: nil)
        secondCentralDelegate = SecondCentralManagerDelegate()
        secondCentralManager = CBCentralManager(delegate: secondCentralDelegate, queue: nil)
        print("initialized central managers")
    }
}

3. 额外说明

  • Apple官方并未限制同时运行多个CBCentralManager实例,只要每个实例的代理被正确持有,就能正常接收状态更新及其他回调。
  • 若不想修改第三方库源码,可尝试使用全局单例CBCentralManager配合库的外部管理器传入接口(若支持),既能避免多实例问题,也无需修改库代码。

内容的提问来源于stack exchange,提问作者Wake

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.07 15:30:55