Swift CoreBluetooth:CentralManager 应该在单独的线程中运行吗?

2024-01-26

现在我在主线程中运行所有内容,到目前为止,我只注意到 UI 变得有点滞后的多次中的一次。

我想知道 utilizint CoreBluetooth 库在并发方面的一般做法是什么?

您能否提供一些示例,具体应该在其他队列中运行什么(如果有的话)?

我对蓝牙的使用:

我扫描两个外围设备,通过发送适当的值作为 CBPeripheralManager 来控制它们,以便使它们开始从 IMU 发送数据(50Hz/100Hz,取决于值)。

我同步和标准化标签中的数据,并使用流媒体将它们写入文件。

传输完成后,我通过按钮触发相关操作来手动发送数据文件。

My code

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

        }

    }
}

}

我总是在后台线程上运行蓝牙活动,因为某些蓝牙 API 调用有可能被阻塞。

我猜想转移到后台的主要候选者是扫描和发现方法,因为这是执行真正硬件操作的地方。

对于我的任务使用大中央快讯 https://developer.apple.com/reference/dispatch足够。

EDIT:GCD使用的最简单的例子:

func peripheral(_ peripheral: CBPeripheral, didUpdateValueFor characteristic: CBCharacteristic, error: Error?) {
    DispatchQueue.main.async { 
        valueLabel.text = peripheral.value.map { String(data: $0, encoding: NSUTF8StringEncoding) }
    }
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Swift CoreBluetooth:CentralManager 应该在单独的线程中运行吗? 的相关文章

  • 对 STL 容器的安全并行只读访问

    我想要访问基于 STL 的容器只读 from parallel运行线程 无需使用任何用户实现的锁定 以下代码的基础是 C 11 并正确实现了该标准 http gcc gnu org onlinedocs libstdc manual usi
  • UIStepper:如何知道用户单击了步进器的哪个按钮(减号或加号按钮)

    我如何知道用户点击了步进器的哪个按钮 减号或加号按钮 IBAction buttonStepper id sender int stepperValue self outletStepper value self label text NS
  • iOS10 iMessage:无法使用 MSConversation 将数据插入 iMessage

    在我的项目中我添加了iMessage Extension但我无法发送选定的数据UITableview 需要发送选定行数据 声明 var savedConversation MSConversation 我想在用户时发送文本didselect
  • 如何获得包含大量图像(50-200)的快速 UICollectionView?

    我在用着UICollectionView在一个显示大量照片 50 200 的应用程序中 我在让它变得活泼 例如像照片应用程序一样活泼 时遇到问题 我有一个习惯UICollectionViewCell with a UIImageView因为
  • 如何检测和处理UIWebView中的HTTP错误代码?

    我想在收到 HTTP 错误 404 等时通知用户 我怎样才能检测到这一点 我已经尝试过实施 void webView UIWebView webView didFailLoadWithError NSError error 但当我收到 40
  • 如何在 SwiftUI 中使用 @FetchRequest 和新的可搜索修饰符?

    是否可以使用新的 searchable结合 FetchRequest 我有这样的代码 struct FooListView View Environment managedObjectContext private var viewCont
  • AVVideoComposition 应用过滤器处理程序不调用

    I want to add an overlay image into a video I use AVVideoComposition and CIFilter to do this but AVAsynchronousCIImageFi
  • UITableView 中具有多个部分的搜索控制器

    我有一个 UIViewController 其中有一个 UITableView 在该表视图内我有多个部分 其中有一些项目 我必须在该表视图内使用项目名称进行搜索 我已经在我的视图控制器中声明了这一点 let searchController
  • 使用文本和进度条填充 DataGridView

    我正在创建一个多线程应用程序 其中每个线程将在我的应用程序中显示为一行DataGridView 我想要一个ProgressBar每行指示相应的线程进度 问题是 这可能吗 如果是这样 怎么办 我添加了类 DataGridView Progre
  • 从实时照片中提取视频部分

    有谁知道如何从实时照片中提取视频部分 我正在开发一个将 Live Photos 转换为 GIF 的应用程序 第一步是从 Live Photo 中获取视频文件 看起来这应该是可能的 因为如果你将手机插入 Mac 你就可以看到单独的图像和视频文
  • 如何从我的应用程序打开 ios Native dialer 应用程序

    我想打开本机拨号器应用程序并允许用户在那里输入电话号码 我想要这个的原因是因为在我的应用程序中 用户需要使用 USSD 代码才能拨打电话 但使用下面的代码没有任何反应 没有任何启动 NSString phoneNumber tel stri
  • 在 iOS8.3 上显示警报视图时不必要地触发 iOS 键盘通知

    我们正在观察 iOS 8 3 上键盘将显示和隐藏通知的异常行为 视图控制器 监听键盘通知 有一个文本字段 单击并点击提交按钮后 该方法首先从文本字段中退出第一响应者 并显示一条警报以通知警告 一切正常 它会关闭键盘并按预期显示警报 也调用
  • 为 Swift 中的Optional提供默认值?

    如果您只想在 nil 的情况下提供默认值 那么在 Swift 中处理可选值的习惯用法似乎过于冗长 if let value optionalValue do something with value else do the same thi
  • 协议扩展,不符合协议

    我正在创建一个名为MyFramework含有LoginProtocol swift它有一些默认行为 import UIKit public protocol LoginProtocol func appBannerImage gt UIIm
  • 应用内购买导致偶尔崩溃

    我在互联网上搜索了这方面的帮助 但没有结果 我的应用程序已在应用程序商店中上线 少数用户报告应用程序在进行应用内购买后冻结并崩溃 我的游戏中唯一的 IAP 它基本上解锁了完整版本 即使他们重新启动设备并尝试继续 设备也会再次崩溃 我无法重现
  • 使用 Objective C 将 html 字符串插入 sqlite 数据库

    我正在使用下面的代码片段将 html 字符串插入 sqlite 数据库 我的代码工作正常 但是当我检索相同的 html 字符串并在 Web 视图中显示时 它不会呈现 一些数据正在被修改 任何人都可以帮助如何插入长 html 字符串存入数据库
  • 为什么 NSOrderedSet 不继承 NSSet?

    当然 有序集是集合的更具体的情况 那么为什么NSOrderedSet继承自NSObject而不是NSSet 我通过了界面NSSet你是对的 有序集似乎满足里氏替换原则 http en wikipedia org wiki Liskov su
  • iOS 10 和 swift 2.3 中支持的InterfaceOrientations

    我正在使用 Xcode 8 GM 并且有一个旧项目需要更新为 iOS 10 我发现我当前使用 Swift 2 2 版本的应用商店构建在 iOS 10 上运行时不支持所需的界面方向功能 简而言之 当我重写supportedInterfaceO
  • UISearchController 在调用时更改状态栏颜色

    我的应用程序中有以下代码 特别是在viewDidLoad 这设置了我的UISearchController self searchController UISearchController alloc initWithSearchResul
  • 与桌面浏览器相比,移动浏览器有多强大? [关闭]

    就目前情况而言 这个问题不太适合我们的问答形式 我们希望答案得到事实 参考资料或专业知识的支持 但这个问题可能会引发辩论 争论 民意调查或扩展讨论 如果您觉得这个问题可以改进并可能重新开放 访问帮助中心 help reopen questi

随机推荐

  • 有没有正确的方法来子类 Tensorflow 的数据集?

    我正在研究可以处理自定义 Tensorflow 数据集的不同方法 并且我习惯于查看PyTorch 的数据集 https pytorch org tutorials beginner basics data tutorial html cre
  • 一个或两个字母后跟 3-4 个数字

    我正在尝试找到正确的正则表达式模式 以允许一两个字母后跟 3 到 5 个数字 最后可选一个字母 最后应该允许非字母数字来包裹字符串 Allowed M394 MP4245 TD493 X4958A V49534 U394U A5909 No
  • Heroku 部署错误:找不到模块“/app/index.js”

    我正在尝试在 Heroku 上部署 mt 应用程序 但总是遇到相同的错误 2016 08 18T10 16 10 988982 00 00 heroku web 1 Starting process with command node in
  • React Native 组件中的 onEnter/onExit 方法 (react-native-router-flux)

    因此 我可以在路由器定义中的应用程序根目录中使用 onEnter onExit 方法 并且它工作得很好
  • 有没有 Doctrine 和 Propel 的比较?

    我看过很多 Doctrine 与 Propel 的比较 但没有一个真正说服我选择 Doctrine 而不是 Propel 我已经使用 Propel 一段时间了 几乎我读到的每一个比较都表明 Propel 没有被很好地记录为第一个问题 而且我
  • ASIHTTPRequest 与 AFNetworking 与 NSUrlRequest

    过去我用过ASIHTTPRequest但现在有NSURLRequest 我们应该使用NSURLRequest现在 有什么缺点吗 对于现在阅读本文的人 我最终使用了AFNetworking正如答案中提到的 https github com A
  • asp.net缓存多线程锁webparts

    我有以下场景 假设我们有两个不同的 Web 部件对相同的数据进行操作 一个是饼图 另一个是数据表 在其 Page Load 中 它们从数据库异步加载数据 加载后将其放入应用程序缓存中以供进一步使用或由其他 Web 部件使用 因此每个 Web
  • 使用 keras tokenizer 处理不在训练集中的新单词

    我目前正在使用 Keras Tokenizer 创建单词索引 然后将该单词索引与导入的 GloVe 字典进行匹配以创建嵌入矩阵 然而 我遇到的问题是 这似乎破坏了使用词向量嵌入的优点之一 因为当使用经过训练的模型进行预测时 如果它遇到不在分
  • JAX-WS/CXF 中的 /encoded 和 /literal 支持

    我从未在 java 中使用过 RPC 调用 所以我对需要研究的一些遗留代码有点困惑 如果可能的话 我希望您能帮助我阐明如何将 CXF 与 RPC 结合使用 1 CXF不支持rpc encoded调用 JAXWS 2 0 不支持 Rpc 编码
  • 不精确浮点常数的警告

    诸如 为什么 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 8 不是 让我想到 最好让编译器警告浮点常量 它舍入到二进制浮点类型中最接近的可表示形式 例如 0 1 和 0 8 以基数 2 浮点舍入 否则它们需要无限量的
  • 如何编译 GnuTLS

    我尝试在 Centos 6 2 上多次编译 GnuTLS 库 但没有成功 这些是步骤 我下载了荨麻2 4 root localhost opt wget http www lysator liu se nisse archive nettl
  • AngularJS 模板。内部JS不执行

    我有很多模板html页面 其中包含js代码 当我的 RouteProvider 加载此模板之一时 JS 不会执行 我不想使用 eval 我可以在外部 js 文件中编写代码并使用 requireJS 但我不知道如何使用 requireJS 停
  • JSON 数组结构变体

    以下是 3 种 JSON 数组结构格式 第一个是 JSON org 上概述的 是我熟悉的 格式 1 People name Sally age 10 name Greg age 10 第二个是命名数组元素的细微变化 我个人并不关心它 你不在
  • 如何在 Eclipse 中包含 javax.jms.* ?

    我正在尝试使用 eclipse 实现 JMS 但是当我尝试保存代码时 它表明javax jms cannot be resolved并且有no suggestions以及它推荐的 我怎样才能包含它并使用它 当我谷歌搜索时 我发现 javax
  • 如何找出我的控制台应用程序正在哪个目录中运行?

    如何找出我的控制台应用程序在 C 中运行的目录 要获取 exe 文件所在的目录 AppDomain CurrentDomain BaseDirectory 获取当前目录 Environment CurrentDirectory
  • Meteor JS 无法对数据进行排序

    我的主体中有一个按钮 单击该按钮时 应按降序排序 当我这样做时 什么也不会发生 我相信我的代码是正确的 但也许我遗漏了一些东西 这是js Tasks new Mongo Collection tasks Template body even
  • 如何使用 pdf.js 渲染 pdf 文件?

    我创建了一个 html 文件 内容如下索引 html
  • 使用 document.getElementById 更改“id=”的值

    这是正确的方法吗 a href class btn load add a a href here a 如
  • 重新加载 React Router 应用程序时出现 404 错误

    当我在本地服务器上重新加载我的应用程序时 一切都很好 但是当我在 gh pages 上托管时重新加载页面时 出现 404 错误 它不会在主页上执行此操作 但会在其他两个页面上执行此操作 这是否与远程托管有关 我对 React Router
  • Swift CoreBluetooth:CentralManager 应该在单独的线程中运行吗?

    现在我在主线程中运行所有内容 到目前为止 我只注意到 UI 变得有点滞后的多次中的一次 我想知道 utilizint CoreBluetooth 库在并发方面的一般做法是什么 您能否提供一些示例 具体应该在其他队列中运行什么 如果有的话 我