扫描BLE设备并将其显示在UITableView中 [英] Scan for BLE devices and present them in an UITableView

查看:57
本文介绍了扫描BLE设备并将其显示在UITableView中的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我尝试找到一种扫描BLE设备并将其显示在UITableView中的方法. BLE设备的扫描,连接,读取和写入功能十分清晰且可以正常运行!因此,我的问题集中在"ScanTableView"和"BletoothManager"类之间的交互上.

I try to find a way to scan for BLE devices and present them in an UITableView. The scan, connect, read and write functionality for BLE devices is clear and works! So my questions are focused on the interaction between the 'ScanTableView' and 'BletoothManager' class.

这是我的两节课:

//  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 ...)之间是否有区别?我记录了异常行...

The shown code works but I'm not able to interact between the two classes. For example I would like to reload my opened ScanTableView from my BluetoothManager class. That's not possible... every time when I try this, I get an exception that I would unwrap an optional. Why? Are there any differences between 'normal' classes and the classes shown in the GUI (UITableView, UIView...)? I documented the exception line...

如果有人可以向我解释在这种情况下该怎么做,那将是非常好的:).

It would be really nice, if anyone could explain me what to do in such situations :).

我很高兴提出任何建议或改进!

推荐答案

就像@ paulw11所说,我必须创建一个委托协议:

Like @paulw11 said, I had to creat a delegate protocol:

protocol BluetoothDelegate: class {

    func ReloadView()
}

此"ReloadView"方法在我的ScanTableView类中声明:

This 'ReloadView' method is declared in my ScanTableView class:

func ReloadView() {
    scanTableView.reloadData()
}

现在,我不得不做一些额外的事情:

Now, I had to do some additional:

  1. 将BluetoothDelegate添加到ScanTableView类
  2. 声明一个变量弱var委托:BluetoothDelegate?"在BluetoothManager类中
  3. 在BluetoothManager类的所需位置使用'delegate?.ReloadView()'调用委托方法
  4. 使用'bluetoothManager?.delegate = self'在ScanTableView中激活委托

就是这样!

这篇关于扫描BLE设备并将其显示在UITableView中的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆