2

Я пытаюсь найти способ сканирования устройств BLE и представить их в UITableView. Функции сканирования, подключения, чтения и записи для устройств BLE понятны и работают! Поэтому мои вопросы сосредоточены на взаимодействии между классами «ScanTableView» и «BletoothManager».Сканирование устройств BLE и их представление в UITableView

Это мои два класса:

// ScanTableView.swift 

import UIKit 

class ScanTableView: UITableViewController { 

    @IBOutlet var scanTableView: UITableView! 

    var bluetoothManager = BluetoothManager?() 
    var tableViewScanTime = 5 
    var timer1: NSTimer! 

    override func viewDidLoad() { 
     super.viewDidLoad() 
     self.refreshControl!.addTarget(self, action: "refresh", forControlEvents: UIControlEvents.ValueChanged) 
    } 

    override func didReceiveMemoryWarning() { 
     super.didReceiveMemoryWarning() 
    } 

    override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int { 
     if let _ = bluetoothManager?.peripheralArray.count { 
      return bluetoothManager!.peripheralArray.count 
     } 
     else { 
      return 0 
     } 
    } 

    override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { 
     let cell = scanTableView.dequeueReusableCellWithIdentifier("scanCell",forIndexPath: indexPath) 
     cell.textLabel!.text = bluetoothManager!.peripheralArray[indexPath.row].name 
     cell.detailTextLabel!.text = bluetoothManager!.peripheralArray[indexPath.row].RSSI 
     return cell 
    } 

    override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) { 
     bluetoothManager!.selectedPeripheral = bluetoothManager!.peripheralArray[indexPath.row] 
     bluetoothManager!.connectPeripheral(bluetoothManager!.selectedPeripheral!) 
    } 

    func refresh() { 
     scanTableView.userInteractionEnabled = false 
     timer1 = NSTimer.scheduledTimerWithTimeInterval(1, target: self, selector: "scanTableViewRefresh", userInfo: nil, repeats: true) 
     bluetoothManager = BluetoothManager() 
    } 

    func scanTableViewRefresh() { 
     scanTableView.reloadData() 
     tableViewScanTime-- 

     if tableViewScanTime <= 0 { 
      timer1.invalidate() 
      bluetoothManager!.CBmanager.stopScan() 
      print("StopScan") 
      tableViewScanTime = 5 
      bluetoothManager!.peripheralArray.sortInPlace({$0.RSSI < $1.RSSI}) 
      self.refreshControl!.endRefreshing() 
      self.scanTableView.userInteractionEnabled = true 
     } 
    } 
} 

// BluetoothManager.swift 

import UIKit 
import CoreBluetooth 

class BluetoothManager: NSObject, CBCentralManagerDelegate, CBPeripheralDelegate { 

    struct BluetoothPeripheral { 
     let name: String 
     let UUID: String 
     let RSSI: String 
     let peripheral: CBPeripheral 

     init(name: String, UUID: String, RSSI: NSNumber, peripheral: CBPeripheral) { 
      self.name = "\(name)" 
      self.UUID = "\(UUID)" 
      self.RSSI = "\(RSSI)" 
      self.peripheral = peripheral 
     } 
    } 

    let DEVICE_NAME:String! = "TEST" 

    //Creat an instance of ScanTableView Class 
    var scanTableView: ScanTableView() 


    var peripheralArray: [BluetoothPeripheral] = [] 
    var selectedPeripheral: BluetoothPeripheral? 
    var characteristicArray: [CBCharacteristic] = [] 
    var CBmanager: CBCentralManager = CBCentralManager() 
    var measurementValue: [[AnyObject?]] = [[]] 

    //Basic functions 
    override init() { 
     super.init() 
     CBmanager = CBCentralManager(delegate: self, queue: nil) 
    } 

    func connectPeripheral(selectedPeripheral: BluetoothPeripheral) { 
     CBmanager.connectPeripheral(selectedPeripheral.peripheral, options: nil) 
    } 

    func disconnectPeripheral(selectedPeripheral: BluetoothPeripheral) { 
     for characteristic in characteristicArray { 
      selectedPeripheral.peripheral.setNotifyValue(false, forCharacteristic: characteristic as CBCharacteristic) 
     } 
     CBmanager.cancelPeripheralConnection(selectedPeripheral.peripheral) 
    } 

    func ScanForPeripherals() { 
     CBmanager.scanForPeripheralsWithServices(nil, options: nil) 
     print("Scanning") 
    } 

    func centralManagerDidUpdateState(central: CBCentralManager) { 
     switch(central.state) { 
     case .PoweredOn: 
      CBmanager.scanForPeripheralsWithServices(nil, options: nil) 
      print("scan") 
     case .PoweredOff, .Resetting, .Unauthorized, .Unsupported, .Unknown: 
      peripheralArray.removeAll() 

      //This invokes an exception 
      //scanTableView.scanTableView.reloadData() 

      print("NO BLE!") 
     } 
    } 

    func centralManager(central: CBCentralManager, didDiscoverPeripheral peripheral: CBPeripheral, advertisementData: [String : AnyObject], RSSI: NSNumber) { 
     let UUID = "\(peripheral.identifier)".substringFromIndex("\(peripheral.identifier)".startIndex.advancedBy(31)) 
     if let peripheralName = peripheral.name { 
      if peripheralName.containsString(DEVICE_NAME) { 
       peripheralArray.append(BluetoothPeripheral(name: peripheral.name!, UUID: UUID, RSSI: RSSI, peripheral: peripheral)) 
       print(peripheralArray) 
      } 
     } 
    } 

    func centralManager(central: CBCentralManager, didConnectPeripheral peripheral: CBPeripheral) { 
     print("Connected") 
     measurementValue.removeAll() 
     peripheral.delegate = self 
     selectedPeripheral!.peripheral.discoverServices(nil) 
    } 

    func centralManager(central: CBCentralManager, didFailToConnectPeripheral peripheral: CBPeripheral, error: NSError?) { 
     print("Fail") 
    } 

    func centralManager(central: CBCentralManager, willRestoreState dict: [String : AnyObject]) { 
     print("Restore") 
    } 

    func centralManager(central: CBCentralManager, didDisconnectPeripheral peripheral: CBPeripheral, error: NSError?) { 
     print("Disconnected") 
    } 

    func peripheral(peripheral: CBPeripheral, didDiscoverServices error: NSError?) { 
     for service in peripheral.services! { 
      peripheral.discoverCharacteristics(nil, forService: service) 
     } 
    } 

    func peripheral(peripheral: CBPeripheral, didDiscoverCharacteristicsForService service: CBService, error: NSError?) { 
     for characteristic in service.characteristics as [CBCharacteristic]!{ 
      if characteristic.properties.contains(CBCharacteristicProperties.Notify) { 
       peripheral.discoverDescriptorsForCharacteristic(characteristic) 
       peripheral.setNotifyValue(true, forCharacteristic: characteristic) 
      } 
     } 
    } 

    func peripheral(peripheral: CBPeripheral, didUpdateNotificationStateForCharacteristic characteristic: CBCharacteristic, error: NSError?) { 
     if characteristic.isNotifying { 
      characteristicArray.append(characteristic as CBCharacteristic) 
      peripheral.readValueForCharacteristic(characteristic) 
     } 
    } 

    func peripheral(peripheral: CBPeripheral, didUpdateValueForCharacteristic characteristic: CBCharacteristic, error: NSError?) { 
     //Store new characteristic values 
    } 
} 

Теперь мои вопросы:

Показанные код работает, но я не в состоянии взаимодействовать между двумя классы. Например, я хотел бы перезагрузить открытый ScanTableView из моего класса BluetoothManager. Это невозможно ... каждый раз, когда я пытаюсь это сделать, я получаю исключение, которое я бы разворачивал. Зачем? Существуют ли различия между «нормальными» классами и классами, отображаемыми в графическом интерфейсе (UITableView, UIView ...)? Я задокументировал строку исключений ...

Было бы очень приятно, если бы кто-нибудь мог объяснить мне, что делать в таких ситуациях :).

Я рад за любые предложения или улучшения!

+0

Можете указать, какая именно строка дает вам ошибку? Вместо использования NSTimer было бы лучше либо установить контроллер табличного представления в качестве делегата для вашего диспетчера Bluetooth, либо создать протокол, чтобы менеджер Bluetooth мог сообщить контроллеру таблицы о недавно обнаруженных устройствах или использовать диспетчер Bluetooth для использования NSNotification для консультирования заинтересованные классы об изменениях – Paulw11

+0

В середине второго класса я прокомментировал 'scanTableView.scanTableView.reloadData()' out. Эта часть вызывает исключение. Я хотел бы использовать модуль NSTimer, чтобы «контролировать», как долго я ищу любые устройства. Поэтому в этом случае я просто ищу 5 секунд. Я не хочу использовать модуль NSNotification, чтобы избежать путаницы с кодом ... Я думаю, у меня есть проблема с правильным экземпляром моего ScanTableView. Я попробовал это с помощью «storyboard.instantiateViewControllerWithIdentifier» («scanTableViewIdentifier») как! ScanTableView ", но без каких-либо успехов. – Passe

+1

Если вы не хотите использовать NSNotification, вам нужно будет использовать протокол и делегирование.Ваш менеджер Bluetooth не может создать экземпляр ScanTableView нового экземпляра, он должен связываться с тем, который уже существует, и это будет тот контроллер, который настроил себя как делегат менеджера bluetooth. – Paulw11

ответ

1

Как @ paulw11 сказал, я должен был создающих протокол делегата:

protocol BluetoothDelegate: class { 

    func ReloadView() 
} 

Этот метод 'ReloadView' объявлен в моем классе ScanTableView:

func ReloadView() { 
    scanTableView.reloadData() 
} 

Теперь, я должен был сделать некоторые дополнительные:

  1. Добавить BluetoothDelegate в класс ScanTableView
  2. Объявить переменную 'weak var delegate: BluetoothDelegate?' в BluetoothManager классе
  3. вызова метод делегата с «делегатом? .ReloadView()» в желанный момент в классе BluetoothManager
  4. Активировать делегат в ScanTableView с помощью «bluetoothManager? .delegate = я»

Это оно!