CoreBluetooth 功能在 Singleton 中不起作用
Posted
技术标签:
【中文标题】CoreBluetooth 功能在 Singleton 中不起作用【英文标题】:CoreBluetooth Functions not working from Singleton 【发布时间】:2018-08-09 15:56:09 【问题描述】:所以我目前在 iPad 和 iPhone 之间设置了蓝牙连接。我在ViewController
中创建了我的测试代码,一切正常。现在,我将其移至 2 个管理器类,一个用于 CBCentralManager
,一个用于 CBPeripheralManager
,上面我创建了一个 BluetoothManager
的类,这是一个单例类,包含有关当前连接设备的一些信息。
但是,当我这样做时,我遇到了一个问题,似乎centralManager.connect()
调用实际上不起作用。我调试了我的整个代码,在那一行之后似乎什么都没有发生,我似乎无法弄清楚为什么会这样或者我实际上哪里出错了。
CentralManager 类
import Foundation
import CoreBluetooth
class CentralManager: NSObject
private var centralManager: CBCentralManager!
var peripherals: [CBPeripheral] = []
override init()
super.init()
centralManager = CBCentralManager(delegate: self, queue: DispatchQueue.main)
// MARK: - CBCentralManager Delegate Methods
extension CentralManager: CBCentralManagerDelegate
func centralManagerDidUpdateState(_ central: CBCentralManager)
switch central.state
case .poweredOn:
centralManager.scanForPeripherals(withServices: [BLEConstants.serviceUUID], options: [CBCentralManagerScanOptionAllowDuplicatesKey: true])
default:
break
func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber)
if !peripherals.contains(peripheral)
peripheral.delegate = self
peripherals.append(peripheral)
centralManager.connect(peripheral, options: nil)
func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral)
peripheral.discoverServices([BLEConstants.serviceUUID])
func centralManager(_ central: CBCentralManager, didDisconnectPeripheral peripheral: CBPeripheral, error: Error?)
guard let peripheralIndex = peripherals.index(of: peripheral), BluetoothManager.shared.deviceCharacteristic[peripheral] != nil else return
peripherals.remove(at: peripheralIndex)
BluetoothManager.shared.deviceCharacteristic.removeValue(forKey: peripheral)
// MARK: - CBPeripheral Delegate Methods
extension CentralManager: CBPeripheralDelegate
func peripheral(_ peripheral: CBPeripheral, didDiscoverServices error: Error?)
for service in peripheral.services!
if service.uuid == BLEConstants.serviceUUID
peripheral.discoverCharacteristics(nil, for: service)
func peripheral(_ peripheral: CBPeripheral, didDiscoverCharacteristicsFor service: CBService, error: Error?)
for characteristic in service.characteristics!
let characteristic = characteristic as CBCharacteristic
if BluetoothManager.shared.deviceCharacteristic[peripheral] == nil
BluetoothManager.shared.deviceCharacteristic[peripheral] = characteristic
func peripheral(_ peripheral: CBPeripheral, didModifyServices invalidatedServices: [CBService])
PeripheralManager 类
class PeripheralManager: NSObject
private var peripheralManager: CBPeripheralManager!
override init()
super.init()
peripheralManager = CBPeripheralManager(delegate: self, queue: nil)
// MARK: - Manage Methods
extension PeripheralManager
func updateAdvertising()
guard !peripheralManager.isAdvertising else peripheralManager.stopAdvertising(); return
let advertisingData: [String: Any] = [CBAdvertisementDataServiceUUIDsKey: BLEConstants.serviceUUID,
CBAdvertisementDataLocalNameKey: BLEConstants.bleAdvertisementKey]
peripheralManager.startAdvertising(advertisingData)
func initializeService()
let service = CBMutableService(type: BLEConstants.serviceUUID, primary: true)
let characteristic = CBMutableCharacteristic(type: BLEConstants.charUUID, properties: BLEConstants.charProperties, value: nil, permissions: BLEConstants.charPermissions)
service.characteristics = [characteristic]
peripheralManager.add(service)
// MARK: - CBPeripheralManager Delegate Methods
extension PeripheralManager: CBPeripheralManagerDelegate
func peripheralManagerDidUpdateState(_ peripheral: CBPeripheralManager)
if peripheral.state == .poweredOn
initializeService()
updateAdvertising()
func peripheralManager(_ peripheral: CBPeripheralManager, didReceiveWrite requests: [CBATTRequest])
for request in requests
if let value = request.value
let messageText = String(data: value, encoding: String.Encoding.utf8)
print(messageText ?? "")
self.peripheralManager.respond(to: request, withResult: .success)
BluetoothManager 类
class BluetoothManager
static let shared = BluetoothManager()
private var centralManager: CentralManager!
private var peripheralManager: PeripheralManager!
var deviceCharacteristic: [CBPeripheral: CBCharacteristic] = [:]
var connectedPeripherals: [CBPeripheral] return centralManager.peripherals
func setup()
centralManager = CentralManager()
peripheralManager = PeripheralManager()
然后在我的ViewController didLoad
我打电话给BluetoothManager.shared.setup()
有谁知道为什么这些设备似乎没有相互连接,或者之后的委托函数没有被调用?
【问题讨论】:
这可能只是一个大胆的猜测,但对象是在 Swift 中使用 'init' 方法实例化的,而不是使用 'setup'。您确定您的 BluetoothManager 已正确初始化吗? @fishinear true 但是我在调用ViewController
时调用了ViewController
中的设置函数,所以我基本上是在为它创建自己的init 函数,因为单例实例化了自己并且我无法控制何时发生这种情况。我做了设置方式,因为在常规初始化中没有一个委托函数被调用
【参考方案1】:
当静态shared
变量使用BluetoothManager()
初始化时,该过程开始。我不确定这在 Swift 中什么时候发生,要么是在程序的一开始,要么是在你第一次使用 BluetoothManager.setup
时。
变量的初始化调用BluetoothManager
的init()
方法。这将实例化一个CentralManager
,并调用它的init()
方法。这将实例化一个CBCentralManager
,它将启动蓝牙进程。
然后调用setup()
,它将实例化一个新的CentralManager
,并带有自己的CBCentralManager
。我可以想象两个CBCentralManager
有问题。
要解决它,不要使用setup()
,而是初始化init()
中的变量。
要调试这种情况,请在所有init()
方法中设置断点。创建析构函数,并在其中放置断点。从技术上讲,无论如何您都需要析构函数,因为您需要从 CBCentralManager
对象中删除自己作为委托。
另请注意,您只能从centralManagerDidUpdateState
调用scanForPeripherals
。 CBCentralManager
在启动时可能已经处于 poweredOn
状态,这可能发生在另一个应用程序同时使用蓝牙时 - 或者当您的第一个 CBCentralManager
对象已经启动它时。在这种情况下,centralManagerDidUpdateState
将永远不会被调用。
【讨论】:
我刚刚创建了设置以控制何时设置管理器。但是我在设置startAdvertising
时确实发现了问题,我将ServiceUUID
作为对象而不是UUID's
的数组传递,这就是它没有按预期工作的原因【参考方案2】:
您确定您的单例已正确初始化吗?
试试这个:
import Foundation
private let singleton = Singleton()
class Singleton
static let sharedInstance : Singleton =
return singleton
()
let cnetralManager = = CBCentralManager(delegate: self, queue: DispatchQueue.main)
【讨论】:
以上是关于CoreBluetooth 功能在 Singleton 中不起作用的主要内容,如果未能解决你的问题,请参考以下文章
使用 AltBeacon 库以 CoreBluetooth 格式做广告
iPhone 4S 上的 Corebluetooth 故障?
ruby 来自http://stackoverflow.com/questions/10039039/why-self-method-of-module-cannot-become-a-singlet