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 
    } 
} 

現在我的問題:

所顯示的代碼工作,但我不能在兩者之間進行交互類。 例如,我想重新從我的BluetoothManager類中打開ScanTableView。這是不可能的...每次當我嘗試這個時,我會得到一個異常,我會打開一個可選的。爲什麼? '正常'類和GUI中顯示的類(UITableView,UIView ...)之間是否有區別?我記錄了異常行...

這將是非常好的,如果任何人都可以解釋我在這種情況下做什麼:)。

我很高興有任何建議或改進!

+0

你能指出哪條線給你錯誤嗎?而不是使用NSTimer,最好將您的表格視圖控制器設置爲您的藍牙管理器的代表,並創建一個協議,以便藍牙管理器可以建議桌面控制器關於新發現的設備,或讓藍牙管理器使用NSNotification建議感興趣的類有關更改 – Paulw11

+0

在第二課中,我評論了'scanTableView.scanTableView.reloadData()'。這部分調用一個異常。我想使用NSTimer模塊來「控制」我搜索任何設備的時間。所以在這種情況下我只搜索了5秒。我不想使用NSNotification模塊,以避免混淆代碼......我想,我的ScanTableView的正確實例有問題。我嘗試了'storyboard.instantiateViewControllerWithIdentifier(「scanTableViewIdentifier」)as! ScanTableView「,但沒有任何成功。 – Passe

+1

如果您不想使用NSNotification,那麼您將需要使用協議和委派。您的藍牙管理器無法實例化ScanTableView的新實例,它需要與已存在的實例進行通信,並且該視圖控制器將自己設置爲藍牙管理器的代表 – 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. 通過使用 'bluetoothManager?.delegate =自我'

激活在ScanTableView委託而已!