Currently my MainViewController can connect to my Bluetooth module and read the data coming from it. Now, I'm trying to read the data from another View Controller.
My Bluetooth Manager is a singleton so that it doesn't get instantiated multiple times. To read and process the data in the appropriate ViewController, I was thinking of using optional delegates. It's working fine when I get to receivedMVC(data: String) but crashes when getting to receivedUVC(data: String)
I get the following error:
[BLE_Tests.MainViewController receivedUVCWithData:]: unrecognized selector sent to instance 0x100d0a9d0 2017-06-22 16:25:58.634682-0700 BLE_Tests[9544:2692419] * Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[BLE_Tests.MainViewController **receivedUVCWithData:]: unrecognized selector sent to instance 0x100d0a9d0'
If I add the receivedUVC(data: String) to my MainViewController, it doesn't crash but doesn't call the receivedUVC from the correct ViewController.
How do I point to the correct selector?
Thank you.
MainViewController.swift
class MainViewController: UIViewController, UITableViewDataSource, UITableViewDelegate, BluetoothDelegate {
@IBOutlet weak var peripheralListTableView: UITableView!
@IBOutlet weak var updateButton: UIButton!
let bluetoothManager = BluetoothManager.getInstance()
override func viewDidLoad() {
super.viewDidLoad()
peripheralListTableView.delegate = self
peripheralListTableView.dataSource = self
bluetoothManager.delegate = self
bluetoothManager.discover()
}
func reloadPeripheralList() {
peripheralListTableView.reloadData()
}
func receivedMVC(data: String) {
print("Hello? \(data)")
}
//MARK: - UITableViewDataSource
}
UpdateViewController.swift
class UpdateViewController: UIViewController, BluetoothDelegate {
let bluetoothManager = BluetoothManager.getInstance()
func receivedUVC(data: String) {
print("Allo: \(data)")
}
}
BluetoothManager.swift
func peripheral(_ peripheral: CBPeripheral, didUpdateValueFor characteristic: CBCharacteristic, error: Error?) {
let stringValue = String(data: characteristic.value!, encoding: String.Encoding.utf8)!
print("Received packet: \(stringValue)")
delegate?.receivedMVC!(data: stringValue) // Delegate method in MainViewController
delegate?.receivedUVC!(data: stringValue) // Delegate method in UpdateViewController
}
[BLE_Tests.MainViewController **receivedUVCWithData:]
This tells you that the MainViewController method receivedUVCWithData: was called, but that class do not implement it. And thats the reason why it's called:
delegate?.receivedUVC!(data: stringValue)
This call will check if the delegate exists and if so it send a message to receivedUVC that must(!) exist. So it will not crash if you call this:
delegate?.receivedUVC?(data: stringValue)
But then I ask myself why you define two different methods in your protocol? Define one mandatory (not optional) method in your protocol, implement it in both UIViewControllers and call this method in BluetoothManager.swift. Then the last set delegate get the data. If both ViewControllers exists at the same time your BluetoothManager needs a delegate1 and a delegate2 and a call to the method on both delegates.