SwiftUI中如何在BluetoothViewModel内设置ConnectedPeripheral环境对象?
解决方案:在SwiftUI中复用CBPeripheral实例
1. 创建ConnectedPeripheral包装类(作为EnvironmentObject)
定义一个符合ObservableObject的包装类,用来持有全局的CBPeripheral实例,通过SwiftUI环境对象实现全应用共享:
import CoreBluetooth import SwiftUI class ConnectedPeripheral: ObservableObject { // @Published标记属性,变化时自动通知视图更新 @Published var peripheral: CBPeripheral? // 封装更新方法,让逻辑更清晰 func update(with newPeripheral: CBPeripheral?) { self.peripheral = newPeripheral } }
2. 在应用入口注入环境对象
在App结构体中初始化ConnectedPeripheral和BluetoothViewModel,将两者注入视图环境,确保所有子视图可访问:
@main struct BluetoothDemoApp: App { @StateObject private var connectedPeripheral = ConnectedPeripheral() @StateObject private var bluetoothViewModel: BluetoothViewModel init() { let peripheral = ConnectedPeripheral() self._connectedPeripheral = StateObject(wrappedValue: peripheral) self._bluetoothViewModel = StateObject(wrappedValue: BluetoothViewModel(connectedPeripheral: peripheral)) } var body: some Scene { WindowGroup { ContentView() .environmentObject(connectedPeripheral) .environmentObject(bluetoothViewModel) } } }
3. 在BluetoothViewModel中更新环境对象
让BluetoothViewModel持有ConnectedPeripheral的引用,在蓝牙连接/断开回调中直接更新其peripheral属性:
import CoreBluetooth import SwiftUI class BluetoothViewModel: NSObject, CBCentralManagerDelegate, ObservableObject { private let centralManager: CBCentralManager private let connectedPeripheral: ConnectedPeripheral // 初始化时传入共享的ConnectedPeripheral实例 init(connectedPeripheral: ConnectedPeripheral) { self.connectedPeripheral = connectedPeripheral self.centralManager = CBCentralManager(delegate: nil, queue: DispatchQueue.main) super.init() centralManager.delegate = self } // 蓝牙设备连接成功回调 func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) { connectedPeripheral.update(with: peripheral) // 设置peripheral代理,处理服务/特征发现 peripheral.delegate = self peripheral.discoverServices(nil) } // 蓝牙设备断开回调 func centralManager(_ central: CBCentralManager, didDisconnectPeripheral peripheral: CBPeripheral, error: Error?) { connectedPeripheral.update(with: nil) } // 扫描蓝牙设备逻辑 func startScanning() { centralManager.scanForPeripherals(withServices: nil, options: nil) } } // 扩展实现CBPeripheralDelegate,处理服务/特征相关逻辑 extension BluetoothViewModel: CBPeripheralDelegate { func peripheral(_ peripheral: CBPeripheral, didDiscoverServices error: Error?) { guard let services = peripheral.services else { return } for service in services { peripheral.discoverCharacteristics(nil, for: service) } } }
4. 在其他视图中使用共享的CBPeripheral
在任意子视图中,通过@EnvironmentObject获取ConnectedPeripheral,直接使用其peripheral属性:
struct DeviceControlView: View { @EnvironmentObject private var connectedPeripheral: ConnectedPeripheral var body: some View { VStack(spacing: 20) { if let peripheral = connectedPeripheral.peripheral { Text("当前连接设备: \(peripheral.name ?? "未知设备")") Button("发送指令") { sendCommand(to: peripheral) } } else { Text("未连接蓝牙设备") } } .padding() } private func sendCommand(to peripheral: CBPeripheral) { // 实现向设备发送数据的逻辑,例如写入特征值 guard let service = peripheral.services?.first(where: { $0.uuid == YourServiceUUID }), let characteristic = service.characteristics?.first(where: { $0.uuid == YourCharacteristicUUID }) else { return } let data = "Hello Bluetooth".data(using: .utf8) peripheral.writeValue(data!, for: characteristic, type: .withResponse) } }
5. 监听@Published属性变化(可选)
如果选择在BluetoothViewModel中添加@Published var peripheral: CBPeripheral?,可通过以下方式监听变化:
方式1:在视图中用.onReceive监听
struct ContentView: View { @EnvironmentObject private var viewModel: BluetoothViewModel var body: some View { Text("蓝牙连接状态") .onReceive(viewModel.$peripheral) { newPeripheral in if let peripheral = newPeripheral { print("设备已连接: \(peripheral.name ?? "未知")") } else { print("设备已断开") } } } }
方式2:在ViewModel内部用Combine监听
class BluetoothViewModel: NSObject, CBCentralManagerDelegate, ObservableObject { @Published var peripheral: CBPeripheral? private var cancellables = Set<AnyCancellable>() override init() { super.init() // 监听peripheral属性变化 $peripheral .sink { [weak self] newPeripheral in guard let self = self else { return } if let peripheral = newPeripheral { peripheral.delegate = self peripheral.discoverServices(nil) } } .store(in: &cancellables) } // ...其他蓝牙逻辑 }
内容的提问来源于stack exchange,提问作者lcj
相关产品推荐
相关产品推荐

