Итак, в настоящее время у меня установлено соединение Bluetooth между 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()
Кто-нибудь знает, почему устройства, похоже, не подключаются друг к другу или, может быть, функции делегирования после этого просто не вызываются?
@fishinear true, но я вызываю функцию настройки в ViewController, когда вызывается didLoad, поэтому я в основном создаю для нее свою собственную функцию инициализации, поскольку синглтон создает сам себя, и я не могу контролировать, когда это произойдет. Я выполнил настройку, потому что в обычном запуске ни одна из функций делегата не вызывалась





Процесс начинается, когда статическая переменная shared инициализируется с помощью BluetoothManager(). Я не уверен, когда это происходит в Swift, это либо в самом начале программы, либо когда вы впервые используете BluetoothManager.setup.
Инициализация переменной вызывает метод init() в BluetoothManager. Это создаст экземпляр CentralManager, и будет вызван его метод init(). Это создаст экземпляр CBCentralManager, который запустит процесс Bluetooth.
Затем вы вызываете setup(), который создает экземпляр нового CentralManager с собственным CBCentralManager. Я могу представить, что с двумя CBCentralManager что-то пошло не так.
Чтобы решить эту проблему, не используйте setup(), а вместо этого инициализируйте переменные в init().
Чтобы отладить такую ситуацию, установите точки останова во всех методах init(). Создайте деструкторы и поместите в них точки останова. Технически вам в любом случае нужны деструкторы, потому что вам нужно удалить себя как делегата из объекта CBCentralManager.
Также обратите внимание, что вы вызываете scanForPeripherals только из centralManagerDidUpdateState. CBCentralManager может уже быть в состоянии poweredOn при запуске, это может произойти, когда другое приложение использует Bluetooth в то же время - или когда ваш первый объект CBCentralManager уже запустил его. В этом случае centralManagerDidUpdateState никогда не будет вызван.
Я просто создал настройку, чтобы контролировать, когда настраиваются менеджеры. Однако я обнаружил проблему при настройке startAdvertising. Я передал ServiceUUID как объект, а не как массив UUID's, поэтому он работал не так, как ожидалось.
Вы уверены, что ваш синглтон правильно инициализирован?
Попробуй это:
import Foundation
private let singleton = Singleton()
class Singleton {
static let sharedInstance : Singleton = {
return singleton
}()
let cnetralManager = = CBCentralManager(delegate: self, queue: DispatchQueue.main)
}
Это может быть просто догадка, но объекты создаются с помощью метода init в Swift, а не с помощью setup. Вы уверены, что ваш BluetoothManager инициализирован правильно?