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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.17 22:01:17