Core Bluetooth:CBPeripheralState连接成功后未更新的解决方法
解决蓝牙设备连接状态不更新的问题
问题根源
你的视图无法感知CBPeripheral的state变化,因为CBPeripheral不是SwiftUI的可观察对象,仅靠@Binding无法触发视图刷新——SwiftUI只会在@State、@ObservedObject、@Published等可观察属性变化时重新渲染视图。
解决方案
通过创建一个遵循ObservableObject的ViewModel,监听CBPeripheral的状态变化并通知视图更新:
1. 实现PeripheralViewModel
这个类负责持有外设、监听状态变化,并通过@Published属性向外暴露状态字符串:
import CoreBluetooth import Combine class PeripheralViewModel: NSObject, ObservableObject, CBPeripheralDelegate { @Published var peripheral: CBPeripheral @Published var stateString: String init(peripheral: CBPeripheral) { self.peripheral = peripheral // 初始化时设置初始状态 switch peripheral.state { case .disconnected: stateString = "Not Connected" case .connecting: stateString = "Connecting" case .connected: stateString = "Connected" case .disconnecting: stateString = "Disconnecting" @unknown default: stateString = "Unknown" } super.init() self.peripheral.delegate = self } // 监听外设状态更新回调 func peripheral(_ peripheral: CBPeripheral, didUpdateState state: CBPeripheralState) { switch state { case .disconnected: stateString = "Not Connected" case .connecting: stateString = "Connecting" case .connected: stateString = "Connected" case .disconnecting: stateString = "Disconnecting" @unknown default: stateString = "Unknown" } } }
2. 修改原视图使用ViewModel
将原来的@Binding var peripheral替换为@ObservedObject var viewModel,直接绑定ViewModel中的状态字符串:
struct DeviceRowView: View { @ObservedObject var viewModel: PeripheralViewModel @Binding var pincode: String let id: Int var body: some View { HStack(spacing: 10) { Text(String(id)) Spacer() Text(viewModel.peripheral.name ?? "name") Spacer() Text(viewModel.stateString) .foregroundColor(.secondary) NavigationLink(destination: DeviceSettingsView(pincode: $pincode, deviceName: viewModel.peripheral.name!)) { Image(systemName: "info.circle") .resizable() .scaledToFit() .frame(width: 20, height: 20) } .buttonStyle(PlainButtonStyle()) } .padding() .font(.headline) } }
3. 使用视图时初始化ViewModel
在父视图中创建ViewModel实例并传入:
// 示例父视图代码 struct DeviceListView: View { @State var peripherals: [CBPeripheral] = [] @State var pincode: String = "" var body: some View { List(peripherals.enumerated(), id: \.element.identifier) { index, peripheral in DeviceRowView(viewModel: PeripheralViewModel(peripheral: peripheral), pincode: $pincode, id: index + 1) } } }
关键注意点
- 必须确保ViewModel设置了
peripheral.delegate = self,否则无法收到didUpdateState回调。 - 如果在列表中使用,建议以外设的
identifier作为列表的id,避免视图复用导致的状态混乱。
内容的提问来源于stack exchange,提问作者dor sahar
相关产品推荐
相关产品推荐

