WorkAround:
I am creating a utility class let's say BLEScanManager
, which is responsible to scan nearby BLE devices. The only job of the utility class is to scan BLE devices and make a list of it.
The other classes can create an object of this BLEScanManager
and get an array of BLE devices, like [Bluetooth]
(here Bluetooth
is a custom modal class).
Now to scan BLE devices, I have created the extension of BLEScanManager
in the same class and override its delegate methods like below:
import UIKit
import CoreBluetooth
protocol BLEScanDelegate {
func reloadDeviceList()
}
internal class BLEScanManager: NSObject {
private var centralManager: CBCentralManager?
var devices : [Bluetooth] = []
var delegate: BLEScanDelegate?
override init() {
super.init()
centralManager = CBCentralManager(delegate: self, queue: .main)
}
// MARK:- Custom methods
func isScanning() -> Bool {
return centralManager?.isScanning ?? false
}
func stopScanning() {
centralManager?.stopScan()
}
func startScanning() {
devices.removeAll()
let options: [String: Any] = [CBCentralManagerScanOptionAllowDuplicatesKey:
NSNumber(value: false)]
centralManager?.scanForPeripherals(withServices: nil, options: options)
}
}
extension BLEScanManager : CBCentralManagerDelegate {
func centralManagerDidUpdateState(_ central: CBCentralManager) {
switch central.state {
case .unknown: print("central.state is .unknown")
case .resetting: print("central.state is .resetting")
case .unsupported: print("central.state is .unsupported")
case .unauthorized: print("central.state is .unauthorized")
case .poweredOff: print("central.state is .poweredOff")
case .poweredOn: print("central.state is .poweredOn")
self.startScanning()
@unknown default: fatalError("unknow state")
}
}
func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber) {
print("Discovered \(peripheral)")
var bluetooth = Bluetooth()
bluetooth.name = peripheral.name
bluetooth.identifier = peripheral.identifier.uuidString
bluetooth.state = peripheral.state.rawValue
bluetooth.advertisementData = advertisementData
let power = advertisementData[CBAdvertisementDataTxPowerLevelKey] as? Double
let value: Double = pow(10, ((power ?? 0 - Double(truncating: RSSI))/20))
bluetooth.signalStrength = String(describing: value.round)
// Do not add duplicate device
let fitlerArray : [Bluetooth] = devices.filter { $0.identifier == bluetooth.identifier}
if fitlerArray.count == 0 {
devices.append(bluetooth)
}
self.delegate?.reloadDeviceList()
}
}
The thing here is these methods are exposed in the other classes too.
For example:
I have created an object of BLEScanManager
in other class BLEListViewController
to show a list of BLE device in UITableView
.
class BLEListViewController: UITableViewController {
var scanManager: BLEScanManager!
}
I can access CBCentralManagerDelegate
delegate methods in BLEListViewController
class using an object scanManager
.
Like below,
self.scanManager.centralManager?(<#T##central: CBCentralManager##CBCentralManager#>, didConnect: <#T##CBPeripheral#>)
This should expose the internal utility delegate methods to the outside world.
Question is how to stop exposing these delegates?
Please note that, if I use internal
keyword it only hides that specific method. But it still allows accessing all other CBCentralManagerDelegate
methods.