Ios Swift CoreBluetooth:CentralManager是否应该在单独的线程中运行?
现在我在主线程中运行一切,到目前为止,我只注意到很多次中有一次UI变得有点滞后 我想知道关于并发性的Utizint CoreBooth库的一般做法是什么 您能否提供一些例子,说明在其他队列中应该运行什么,如果有的话 我对蓝牙的使用: 我扫描两个外围设备,通过发送合适的值作为CBPeripheralManager来控制它们,以使它们开始从IMU发送数据(50Hz/100Hz,取决于值) 我同步和规范化标记中的数据,并使用streamer将它们写入文件 传输完成后,我通过触发按钮的相关操作手动发送数据文件 我的代码Ios Swift CoreBluetooth:CentralManager是否应该在单独的线程中运行?,ios,swift,multithreading,bluetooth,core-bluetooth,Ios,Swift,Multithreading,Bluetooth,Core Bluetooth,现在我在主线程中运行一切,到目前为止,我只注意到很多次中有一次UI变得有点滞后 我想知道关于并发性的Utizint CoreBooth库的一般做法是什么 您能否提供一些例子,说明在其他队列中应该运行什么,如果有的话 我对蓝牙的使用: 我扫描两个外围设备,通过发送合适的值作为CBPeripheralManager来控制它们,以使它们开始从IMU发送数据(50Hz/100Hz,取决于值) 我同步和规范化标记中的数据,并使用streamer将它们写入文件 传输完成后,我通过触发按钮的相关操作手动发送数
class BluetoothTagController: NSObject, CBCentralManagerDelegate, CBPeripheralDelegate, CBPeripheralManagerDelegate{
static let sharedInstance = BluetoothTagController()
var transferCharacteristic:CBMutableCharacteristic!
var centralManager : CBCentralManager!
var sensorTagPeripheral : CBPeripheral!
var synchronizer:DataSynchronizer!
var sensorTagPeripheralArray : [CBPeripheral] = []
var peripheralManager: CBPeripheralManager!
var bluetoothIsON:Bool = false
var tag1Updating:Bool = false
var tag2Updating:Bool = false
var tag1Changed:Bool = false
var tag2Changed:Bool = false
var tagsIds:[String] = []
var peripheralCounter:Int = 0
var peripheralCounter2:Int = 0
var writeCounter:Int = 0
var timerSet:Bool = false
var haveBeenStarted:Bool = false
override init()
{
super.init()
centralManager = CBCentralManager(delegate: self, queue: nil)
peripheralManager = CBPeripheralManager(delegate: self, queue: nil)
self.synchronizer = DataSynchronizer(frequency: 1)
}
func peripheralManager(_ peripheral: CBPeripheralManager, didAdd service: CBService, error: Error?) {
print("WATCH OUT")
// print(service)
}
func setHaveBeenStarted( haveBeen: Bool) {
haveBeenStarted = haveBeen
}
func peripheralManager(_ peripheral: CBPeripheralManager, central: CBCentral, didSubscribeTo characteristic: CBCharacteristic) {
print("subscription started")
var intVal: NSInteger = 0
if haveBeenStarted == true {
intVal = 2
}
let valueData:Data = Data(buffer: UnsafeBufferPointer(start: &intVal, count: 1))
var didSend:Bool = self.peripheralManager.updateValue(valueData, for: self.transferCharacteristic, onSubscribedCentrals: nil)
print(didSend)
}
func peripheralManagerDidUpdateState(_ peripheral: CBPeripheralManager) {
if peripheral.state != .poweredOn
{
print("no power")
self.bluetoothIsON = false
return
}
self.bluetoothIsON = true
print("powered on")
let serviceCBUUID = CBUUID(string: "5DC90000-8F79-462B-98D7-C1F8C766FA47")
let transferService:CBMutableService = CBMutableService(type: serviceCBUUID, primary: true)
let characteristicBUUID = CBUUID(string: "5DC90001-8F79-462B-98D7-C1F8C766FA47")
var intVal: NSInteger = 2
let valueData:Data = Data(buffer: UnsafeBufferPointer(start: &intVal, count: 1))
let transferCharacteristic = CBMutableCharacteristic(type: characteristicBUUID, properties: .notify, value: nil, permissions: .readable)
self.transferCharacteristic = transferCharacteristic
transferService.characteristics = [transferCharacteristic as CBCharacteristic]
self.peripheralManager.add(transferService)
self.peripheralManager.startAdvertising(nil)
}
func peripheralManagerDidStartAdvertising(_ peripheral: CBPeripheralManager, error: Error?) {
}
func peripheralManager(_ peripheral: CBPeripheralManager, didReceiveRead request: CBATTRequest) {
print("didReceiveReadRequest")
//
}
func peripheralManager(_ peripheral: CBPeripheralManager, central: CBCentral, didUnsubscribeFrom characteristic: CBCharacteristic) {
print("Unsubscribed")
// var intVal: NSInteger = 0
// let valueData:Data = Data(buffer: UnsafeBufferPointer(start: &intVal, count: 1))
// self.peripheralManager.updateValue(valueData, for: self.transferCharacteristic, onSubscribedCentrals: nil)
}
/******* CBCentralManagerDelegate *******/
// Check status of BLE hardware
func centralManagerDidUpdateState(_ central: CBCentralManager) {
if central.state == .poweredOn {
// Scan for peripherals if BLE is turned on
central.scanForPeripherals(withServices: nil, options: nil)
}
else {
// Can have different conditions for all states if needed - show generic alert for now
}
}
// Check out the discovered peripherals to find Sensor Tag
func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber) {
print("array2 contains" + "\(self.sensorTagPeripheralArray.count)")
if SensorTag.sensorTagFound(advertisementData) == true {
// Update Status Label'
self.sensorTagPeripheral = peripheral
self.sensorTagPeripheral.delegate = self
self.centralManager.connect(peripheral, options: nil)
if !self.sensorTagPeripheralArray.contains(peripheral)
{
self.sensorTagPeripheralArray.append(peripheral)
self.tagsIds.append("\(peripheral.identifier)")
// self.centralManager.connectPeripheral(peripheral, options: nil)
}
else {
//showAlertWithText(header: "Warning", message: "SensorTag Not Found")
}
}
}
// Discover services of the peripheral
func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) {
print("connected " + "\(peripheral.identifier)")
print("array contains" + "\(self.sensorTagPeripheralArray.count)")
numberOfTagsSending = numberOfTagsSending + 1
peripheral.discoverServices(nil)
}
// If disconnected, start searching again
func centralManager(_ central: CBCentralManager, didDisconnectPeripheral peripheral: CBPeripheral, error: Error?) {
// print("error")
// print(error)
// self.sensorTagPeripheralArray.arrayRemovingObject(peripheral)
// print(sensorTagPeripheralArray)
numberOfTagsSending = numberOfTagsSending - 1
print("removed")
synchronizer.alreadySynced = false
central.scanForPeripherals(withServices: nil, options: nil)
}
func centralManager(_ central: CBCentralManager, willRestoreState dict: [String : Any]) {
print("ciekawe")
}
func peripheral(_ peripheral: CBPeripheral, didDiscoverServices error: Error?) {
print("looking for p services")
print("discovered services " + "\(peripheral.identifier)")
for service in peripheral.services! {
let thisService = service as CBService
if SensorTag.validService(thisService) {
// Discover characteristics of all valid services
peripheral.discoverCharacteristics(nil, for: thisService)
}
}
}
// Enable notification and sensor for each characteristic of valid service
func peripheral(_ peripheral: CBPeripheral, didDiscoverCharacteristicsFor service: CBService, error: Error?) {
// print("discovered characteristic " + "\(peripheral.identifier)")
var enableValue = 1
let enablyBytes = Data(buffer: UnsafeBufferPointer(start: &enableValue, count: 1))
// print("\n")
for charateristic in service.characteristics! {
print(charateristic.uuid)
let thisCharacteristic = charateristic as CBCharacteristic
if SensorTag.validDataCharacteristic(thisCharacteristic) {
// Enable Sensor Notification
print( "valid char")
// print(thisCharacteristic)
peripheral.setNotifyValue(true, for: thisCharacteristic)
if thisCharacteristic.uuid == MagnetometerDataUUID{
peripheral.readValue(for: thisCharacteristic)
}
print("after notify set")
// print(self.sensorTagPeripheral.services)
}
if SensorTag.validConfigCharacteristic(thisCharacteristic) {
// Enable Sensor
print("more valid")
// print(thisCharacteristic)
// for peripheral in self.sensorTagPeripheralArray{
peripheral.writeValue(enablyBytes, for: thisCharacteristic, type: CBCharacteristicWriteType.withResponse)
}
}
}
func centralManager(_ central: CBCentralManager, didFailToConnect peripheral: CBPeripheral, error: Error?) {
print(error)
}
// var streamerTag1 = MyStreamer(fileString: "tag1.txt")
// var streamerTag2 = MyStreamer(fileString: "tag2.txt")
func peripheral(_ peripheral: CBPeripheral, didUpdateValueFor characteristic: CBCharacteristic, error: Error?) {
print(characteristic.value!)
if "\(peripheral.identifier)" == self.tagsIds[0]
{
switch characteristic.uuid
{
case MagnetometerDataUUID:
tag1Compensator.getTrimRegisterData(characteristic.value!)
case IRTemperatureDataUUID:
tag1Temperature = Double(UInt16(littleEndian: (characteristic.value! as NSData).bytes.bindMemory(to: UInt16.self, capacity: characteristic.value!.count).pointee))
case IMUDataUUID:
synchronizer.fillTagArray(characteristic.value!, tag: .first)
default:
return
}
}
else if (self.tagsIds.count > 1) && ("\(peripheral.identifier)" == self.tagsIds[1])
{
switch characteristic.uuid
{
case MagnetometerDataUUID:
tag2Compensator.getTrimRegisterData(characteristic.value!)
case IRTemperatureDataUUID:
tag2Temperature = Double(UInt16(littleEndian: (characteristic.value! as NSData).bytes.bindMemory(to: UInt16.self, capacity: characteristic.value!.count).pointee))
case IMUDataUUID:
synchronizer.fillTagArray(characteristic.value!, tag: .second)
default:
return
}
}
}
}
尝试创建一个操作类,它是Oeration(NSOperation)的子类。 操作等级和使用的样本参考
从上面的链接下载示例项目。尝试创建BlutothOperation类,它是Oeration(NSOperation)的子类。 操作等级和使用的样本参考
从上面的链接下载示例项目。我总是在后台线程上运行bluetooth活动,因为某些bluetooth API调用可能会被阻塞 我猜转移到后台的主要候选对象是扫描和发现方法,因为这是一个执行真正硬件操作的地方 对于我的任务,使用就足够了 编辑:GCD使用的最简单示例:
func peripheral(_ peripheral: CBPeripheral, didUpdateValueFor characteristic: CBCharacteristic, error: Error?) {
DispatchQueue.main.async {
valueLabel.text = peripheral.value.map { String(data: $0, encoding: NSUTF8StringEncoding) }
}
}
我总是在后台线程上运行bluetooth活动,因为某些bluetooth API调用可能会被阻塞 我猜转移到后台的主要候选对象是扫描和发现方法,因为这是一个执行真正硬件操作的地方 对于我的任务,使用就足够了 编辑:GCD使用的最简单示例:
func peripheral(_ peripheral: CBPeripheral, didUpdateValueFor characteristic: CBCharacteristic, error: Error?) {
DispatchQueue.main.async {
valueLabel.text = peripheral.value.map { String(data: $0, encoding: NSUTF8StringEncoding) }
}
}
你好,谢谢你的回复。在
外围设备(uperipal:cbperipal,didUpdateValue for characteristic:CBCharacteristic,error:error?)中侦听更新之类的任务如何?你能提供一个你是如何使用GCD的代码片段吗?据我所知,苹果公司的工程师们也曾对此进行过沟通,CB API的设计是异步的。这就是为什么到处都有回调。我个人从未遇到过任何阻塞呼叫。请您举一个例子好吗?@dcdc我添加了一个例子。@allprog很可能它们都是异步的,但我个人在文档中没有提到过,所以我认为最好不要这样假设。至少同步代码的某些部分是隐藏的,所以我更喜欢将其全部移到后台,以便尽可能精简主线程。无需通过异步调用这些API来增加应用程序的复杂性。您可以安全地调用初始值设定项,或从主队列写入函数。如果您在初始值设定项中使用单独的队列,所有回调都将在那里执行。您好,谢谢您的回复。在外围设备(uperipal:cbperipal,didUpdateValue for characteristic:CBCharacteristic,error:error?)中侦听更新之类的任务如何?你能提供一个你是如何使用GCD的代码片段吗?据我所知,苹果公司的工程师们也曾对此进行过沟通,CB API的设计是异步的。这就是为什么到处都有回调。我个人从未遇到过任何阻塞呼叫。请您举一个例子好吗?@dcdc我添加了一个例子。@allprog很可能它们都是异步的,但我个人在文档中没有提到过,所以我认为最好不要这样假设。至少同步代码的某些部分是隐藏的,所以我更喜欢将其全部移到后台,以便尽可能精简主线程。无需通过异步调用这些API来增加应用程序的复杂性。您可以安全地调用初始值设定项,或从主队列写入函数。如果在初始值设定项中使用单独的队列,则所有回调都将在那里执行。对于核心蓝牙管理器,最好使用专用队列。当应用程序转到后台时,主队列将挂起,因此,如果应用程序处于后台,则您的应用程序将停止响应BT回调。在许多核心蓝牙问题中,您还可以了解到一些其他因素。我的应用程序启用了后台模式,在这种模式下运行良好,您能否提供一些资源?最好为核心蓝牙管理器使用专用队列。当应用程序转到后台时,主队列将挂起,因此,如果应用程序处于后台,则您的应用程序将停止响应BT回调。还有一些其他的因素,你可以在很多核心的蓝牙问题中了解到。我的应用程序已经启用了后台模式,并且在这种模式下运行良好,你能提供一些资源吗?