Swift静态库中停止BLE蓝牙扫描出现异常的问题求助
问题原因及解决方法
核心原因
- CBCentralManager未初始化:静态库中的
BluetoothViewController仅声明了centralManager变量,但未在任何初始化流程中创建实例。直接在APP内使用时,ViewController可能通过UIKit生命周期(如storyboard加载)间接完成必要初始化,但静态库中直接实例化时未触发该流程,导致centralManager为nil,调用stopScan()时抛出异常。 - UIViewController与ObservableObject混用不合理:将UIViewController同时作为ObservableObject使用,静态库中直接实例化时未执行UIViewController的完整初始化逻辑,内部组件(如centralManager)无法正常初始化。
- 空值安全缺失:调用
centralManager.stopScan()时未做nil判断,一旦centralManager未初始化就会崩溃。
解决方法
方法1:重构BLE逻辑,剥离UIViewController依赖(推荐)
将BLE核心逻辑从UIViewController中抽离,单独实现独立的BLEManager类,不再依赖UIKit生命周期:
import CoreBluetooth import Combine class BLEManager: ObservableObject, CBCentralManagerDelegate, CBPeripheralDelegate { private var centralManager: CBCentralManager! var device: CBPeripheral? @Published var devicesFound: [CBPeripheral] = [] var devicesDistance: [Int] = [] // 初始化时创建CBCentralManager实例 init() { centralManager = CBCentralManager(delegate: self, queue: DispatchQueue.main) } // 检查蓝牙状态 var isBluetoothOn: Bool { return centralManager.state == .poweredOn } func startScanning() { guard isBluetoothOn else { return } devicesFound.removeAll() devicesDistance.removeAll() centralManager.scanForPeripherals(withServices: []) } func stopScanning() { // 添加空值安全判断 centralManager?.stopScan() } func connect(dev: CBPeripheral, uida: String) { centralManager?.connect(dev, options: nil) } // 实现蓝牙状态更新代理 func centralManagerDidUpdateState(_ central: CBCentralManager) { // 可在此处理蓝牙状态变化(如提示用户开启蓝牙) } // 发现设备时收集信息 func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber) { guard !devicesFound.contains(peripheral) else { return } devicesFound.append(peripheral) devicesDistance.append(RSSI.intValue) } // 实现其他必要代理方法(如连接成功、失败等) }
项目中使用时直接实例化BLEManager:
import MYStaticLib @ObservedObject private var bleManager = BLEManager() DispatchQueue.main.asyncAfter(deadline: .now() + 2.0) { bleManager.stopScanning() guard !bleManager.devicesFound.isEmpty, let minDistance = bleManager.devicesDistance.min(), let index = bleManager.devicesDistance.firstIndex(of: minDistance) else { return } print("Devices Found : \(bleManager.devicesFound.count)") print("Device With Minimum Distance : \(minDistance)") print("Device With Minimum Distance Index : \(index)") bleManager.device = bleManager.devicesFound[index] self.connect(dev: bleManager.device!, uida: uida) }
方法2:修正原ViewController的初始化逻辑(保留ViewController场景)
如果必须保留BluetoothViewController,需确保其初始化流程中创建centralManager实例:
class BluetoothViewController: UIViewController, ObservableObject, CBCentralManagerDelegate, CBPeripheralDelegate { private var centralManager: CBCentralManager! var device: CBPeripheral? @Published var devicesFound : [CBPeripheral] = [] var devicesDistance : [Int] = [] // 重写初始化方法,确保centralManager被创建 override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) { super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil) setupCentralManager() } required init?(coder: NSCoder) { super.init(coder: coder) setupCentralManager() } private func setupCentralManager() { centralManager = CBCentralManager(delegate: self, queue: DispatchQueue.main) } var isBluetoothOn: Bool { return centralManager?.state == .poweredOn ?? false } func startScanning () { guard isBluetoothOn else { return } devicesFound.removeAll() devicesDistance.removeAll() centralManager?.scanForPeripherals(withServices: []) } func stopScanning (){ centralManager?.stopScan() } func connect(dev:CBPeripheral, uida : String){ centralManager?.connect(dev,options: nil) } // 实现代理方法... }
方法3:临时空值安全修复
在stopScanning方法中添加nil判断,避免崩溃(仅作为临时方案,不能解决根本问题):
func stopScanning (){ centralManager?.stopScan() }
内容的提问来源于stack exchange,提问作者Jawad Abbasi
相关产品推荐
相关产品推荐

