2016-10-04 14 views
0

今のところ私はメインスレッドですべてを実行していますが、これまでは何度もUIが少し遅れていることに気付きました。Swift CoreBluetooth:CentralManagerを別のスレッドで実行する必要がありますか?

私は、utilisint CoreBluetoothライブラリの一般的な実践が並行性についてどう思っていますか?

他のキューで実行する必要があるものがあれば、いくつか例を挙げてください。

ブルートゥースの私の使用:

私は彼らがIMU(値に応じて、50Hzの/ 100Hzの)からのデータの送信を開始させるためにCBPeripheralManagerようapproapriate値を送信することによって、それらを制御する、二つの周辺機器をスキャン。

タグからデータを同期化して標準化し、ストリーマを使用してファイルに書き出します。

送信が完了したら、関連する操作をボタンから手動で送信します。

私のコード

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 

     } 

    } 
} 

} 
+0

コアのBluetoothマネージャのための専用のキューを使用することが好ましいです。メインキューは、アプリケーションがバックグラウンドになると中断され、バックグラウンドでBTコールバックへの応答を停止します。多くのSOコア - ブルートゥースの質問で読むことができる他の要因もいくつかあります。 – allprog

+0

私のアプリはバックグラウンドモードを有効にしていて、このモードで正常に機能しています。 – DCDC

答えて

2

私はいつもバックグラウンドスレッドでブルートゥースアクティビティを実行しています。ブルートゥースAPIコールのいくつかがブロックしている可能性があるからです。

私はバックグラウンドに移行する主な候補は、実際のハードウェア操作が実行される場所であるため、スキャンとメソッドの検出です。

私の仕事はGrand Central 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) } 
    } 
} 
+0

ご返信ありがとうございます。周辺機器(_周辺機器:CBPeripheral、didUpdateValueFor特性:CBCharacteristic、エラー:エラー?)メソッドで更新をリッスンするようなタスクはどうでしょうか?コードスニペットでGCDの使い方を教えてください。 – DCDC

+0

私が知る限り、これはAppleのエンジニアによっても伝えられていますが、CB APIは非同期に設計されています。これは、その場にコールバックがある理由です。私は個人的にブロッキングコールが発生したことはありません。あなたは、例を挙げてください。 – allprog

+0

@dcdc例を追加しました。 – slashdot

関連する問題