0

I am having trouble scanning for Bluetooth devices on an app I am building as part of a group project. The code for the view is as follows:

import UIKit
import CoreBluetooth

class bluetoothConnectViewController: UIViewController, UITableViewDelegate, CBCentralManagerDelegate, UITableViewDataSource {

    //-----------------------
    // MARK: Variables
    //-----------------------

    var centralManager: CBCentralManager?
    var peripherals = Array<CBPeripheral>()

    //-----------------------
    // MARK: Outlets
    //-----------------------

    @IBOutlet weak var tableView: UITableView!

    //-----------------------
    // MARK: Core Functions
    //-----------------------

    override func viewDidLoad() {
        super.viewDidLoad()

        //Initialise CoreBluetooth Central Manager
        centralManager = CBCentralManager(delegate: self, queue: DispatchQueue.main, options: nil)

        // Table pull to refresh
        let refreshControl = UIRefreshControl()
        refreshControl.addTarget(self, action: #selector(refresh(_:)), for: .valueChanged)

        tableView.refreshControl = refreshControl

        tableView.delegate = self
        tableView.dataSource = self
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }

    //-----------------------
    // MARK: Custom Functions
    //-----------------------

    func refresh(_ refreshControl: UIRefreshControl) {
        // Do your job, when done:
        refreshControl.endRefreshing()
    }

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return peripherals.count
    }

    func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
        return "Connect to device"
    }

    func numberOfSections(in tableView: UITableView) -> Int {
        return 1
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        var cell  = tableView.dequeueReusableCell(withIdentifier: "cell")

        if cell == nil {
            cell = UITableViewCell(style: .default, reuseIdentifier: "cell")
        }

        let peripheral = peripherals[indexPath.row]
        cell?.textLabel?.text = peripheral.name

        return cell!
    }

    //-----------------------
    // MARK: BLE Functions
    //-----------------------

    func centralManagerDidUpdateState(_ central: CBCentralManager) {
        if (central.state == .poweredOn){
            self.centralManager?.scanForPeripherals(withServices: nil, options: nil)
        }
        else {
            let alert = UIAlertController(title: "Bluetooth not enabled", message: "Enable bluetooth to scan for devuices", preferredStyle: .actionSheet)

            alert.addAction(UIAlertAction(title: "Ok", style: .cancel, handler: nil))
            alert.addAction(UIAlertAction(title: "Settings", style: .default, handler: { (UIAlertAction) in
                let url = URL(string: "prefs:root=Bluetooth")!
                UIApplication.shared.open(url, options: [:], completionHandler: nil)

            }))
        }
    }

    func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber) {
        peripherals.append(peripheral)
        tableView.reloadData()
    }
}

This gives me the following result when scanning using Bluetooth

UITableView displaying Bluetooth devices

Occasionally it will list my laptop only once but it is intermittent, please can let me know what I am doing wrong?

jb167897
  • 37
  • 5
  • Seems you are adding same CBPeripheral object in peripherals array. You have to compare the identifier property of CBPeripheral object obtained in the didDiscover method with the identifier property of CBPeripheral objects in the array. – Aravind Bhuvanendran Apr 12 '17 at 10:32
  • It's the same issue explained there: http://stackoverflow.com/questions/43351664/why-is-corebluetooth-discovering-the-same-peripheral-again-and-again-and-again "Agressive advertising". – Larme Apr 13 '17 at 09:03

3 Answers3

1

It seems that the same CBPeripheral object is inserted again into peripheral array.

You have to compare the identifier property of CBPeripheral object obtained in the didDiscover method with the identifier property of CBPeripheral objects in the peripheral array before adding.

1

In didDiscover method every time you need to compare CDUUID which is property of CBPeripheral which is already available in peripheral array. if not exist then you need to insert in array otherwise leave it.

you got CBUUID using this line CBUUID *uuid = peripheral.UUID; and you check this uuid are already exist in array or not.

1

Peripherals will continue to broadcast data, so the delegate method centralManager(_:didDiscover:advertisementData:rssi:) will receive multiple times.

To solve this problem you can replace type of peripherals using Set, or determines whether the peripheral has been included before appending

Zhang
  • 394
  • 2
  • 11
  • I would check the peripheral.identifier for uniqueness rather than assuming there is a 1:1 mapping of CBPeripheral instances to discovered devices. I believe the framework can give you differing instances for the same device. – CuriousRabbit Apr 12 '17 at 21:56