SWIFT - BLE communications - ios

I've got a SWIFT application that have to send a value to my Arduino with Bluetooth LowEnergy module!
I've done correctly the search and connection parts but I'm not able to send and receive any data.
Here is my code to get a list of BLE devices available and put all this in a table view then after click in a cell the app provide to connect the device with them!
All this works perfectly but I don't know to send for example a "a" character from app to BLE and get back the answer from arduino to app!
import UIKit
import CoreBluetooth
class BluetoothList: UITableViewController,CBCentralManagerDelegate, CBPeripheralDelegate {
var listValue = [Lista]()
var Blue: CBCentralManager!
var conn: CBPeripheral!
var a: String!
var char: CBCharacteristic!
func centralManager(central: CBCentralManager, didDiscoverPeripheral peripheral: CBPeripheral, advertisementData: [String : AnyObject], RSSI: NSNumber) {
if (peripheral.name == a){
self.conn = peripheral
self.conn.delegate = self
Blue.stopScan()
Blue.connectPeripheral(self.conn, options: nil)
self.performSegueWithIdentifier("ConnectionSegue", sender: nil)
}
else{
listValue = [
Lista(Name: peripheral.name!, RSS: RSSI.stringValue)
]
self.tableView.reloadData()
}
}
func centralManager(central: CBCentralManager, didConnectPeripheral peripheral: CBPeripheral) {
peripheral.delegate = self
peripheral.discoverServices(nil)
}
func peripheral(peripheral: CBPeripheral, didDiscoverServices error: NSError?) {
if let servicePeripheral = peripheral.services! as [CBService]!{
for service in servicePeripheral{
peripheral.discoverCharacteristics(nil, forService: service)
}
}
}
func peripheral(peripheral: CBPeripheral, didDiscoverCharacteristicsForService service: CBService, error: NSError?) {
if let characterArray = service.characteristics! as [CBCharacteristic]!{
for cc in characterArray {
if(cc.UUID.UUIDString == "FF05"){
print("OKOK")
peripheral.readValueForCharacteristic(cc)
}
}
}
}
func peripheral(peripheral: CBPeripheral, didUpdateValueForCharacteristic characteristic: CBCharacteristic, error: NSError?) {
if (characteristic.UUID.UUIDString == "FF05"){
let value = UnsafePointer<Int>((characteristic.value?.bytes.memory)!)
print("\(value)")
}
}
func centralManagerDidUpdateState(central: CBCentralManager){
switch(central.state){
case .PoweredOn:
Blue.scanForPeripheralsWithServices(nil, options:nil)
print("Bluetooth is powered ON")
case .PoweredOff:
print("Bluetooth is powered OFF")
case .Resetting:
print("Bluetooth is resetting")
case .Unauthorized:
print("Bluetooth is unauthorized")
case .Unknown:
print("Bluetooth is unknown")
case .Unsupported:
print("Bluetooth is not supported")
}
}
override func viewDidLoad() {
super.viewDidLoad()
Blue = CBCentralManager(delegate: self, queue: nil)
}
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
let currentCell = tableView.cellForRowAtIndexPath(tableView.indexPathForSelectedRow!)! as UITableViewCell
a = currentCell.textLabel?.text
Blue = CBCentralManager(delegate: self, queue: nil)
}
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
#IBAction func Reload_BTN(sender: AnyObject) {
self.tableView.reloadData()
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.listValue.count
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cella = self.tableView.dequeueReusableCellWithIdentifier("Cella", forIndexPath: indexPath)
let Lista = self.listValue[indexPath.row]
cella.textLabel?.text = Lista.Name
cella.accessoryType = UITableViewCellAccessoryType.DisclosureIndicator
return cella
}

The following code is for Swift 3 (XCode 8 Beta 6). It's an example using the standard UUIDs for serial ports like the ones on some commercial modules. So the declarations for the service and characteristics should look like this:
private let UuidSerialService = "6E400001-B5A3-F393-E0A9-E50E24DCCA9E"
private let UuidTx = "6E400002-B5A3-F393-E0A9-E50E24DCCA9E"
private let UuidRx = "6E400003-B5A3-F393-E0A9-E50E24DCCA9E"
And then your delegate's method for the didDiscoverCharacteristic can be something like this:
public func peripheral(_ peripheral: CBPeripheral, didDiscoverCharacteristicsFor service: CBService, error: Error?)
{
if let characteristics = service.characteristics {
for characteristic in characteristics {
// Tx:
if characteristic.uuid == CBUUID(string: UuidTx) {
print("Tx char found: \(characteristic.uuid)")
txCharacteristic = characteristic
}
// Rx:
if characteristic.uuid == CBUUID(string: UuidRx) {
rxCharacteristic = characteristic
if let rxCharacteristic = rxCharacteristic {
print("Rx char found: \(characteristic.uuid)")
serialPortPeripheral?.setNotifyValue(true, for: rxCharacteristic)
}
}
}
}
}
For writing to the Tx, something like the following works, where value is an [UInt8]:
let data = NSData(bytes: value, length: value.count)
serialPortPeripheral?.writeValue(data as Data, for: txCharacteristic, type: CBCharacteristicWriteType.withResponse)
Reading?
public func peripheral(_ peripheral: CBPeripheral, didUpdateValueFor characteristic: CBCharacteristic, error: Error?) {
let rxData = characteristic.value
if let rxData = rxData {
let numberOfBytes = rxData.count
var rxByteArray = [UInt8](repeating: 0, count: numberOfBytes)
(rxData as NSData).getBytes(&rxByteArray, length: numberOfBytes)
print(rxByteArray)
}
}
Finally, if you don't know or you are not sure about the services and characteristics of your BLE device, you can look for a free iOS app called "LightBlue". It will discover a device and if you connect to it, it will list all services and characteristics. Just be aware that obvoiusly your app will not be able to access the BLE hardware while LightBlue is connected to your device.

Related

CBPeripheral services are not rediscovered properly after change

I have an iOS Swift 5 project on which CBCentralManager is used to connect to a BLE device. There is a write CBCharacteristic which should be used to write a certain value from the iOS device and after a successful write, the device changes its services adding a new service into its GATT table. CoreBluetooth seems to not recognize the updated services. The BLE device is paired with iOS.
Things tried and what happened:
If you don't implement didModifyServices from CBPeripheralDelegate, CoreBluetooth complains that the services changed but you don't have a method to handle these changes
If you implement didModifyServices, it never gets called and the above message never gets shown
Tried manually rediscovering services after a successful write but the CBPerpiheral returns the old service only, despite the BLE device actually having another one now in the GATT table, as if CoreBluetooth caches the old services and doesn't actually rediscover them
Tried disconnecting and discarding the CBPeripheral instance, in order to rediscover it and reconnect - in this case, the peripheral never gets rediscovered again after disconnecting.
Any ideas what could be possibly done to be able to rediscover a new service?
Relevant CoreBluetooth code:
enum BluetoothStateChange
{
case unknown
case unsupported
case unauthorized
case poweredOff
}
class BluetoothCentralService: NSObject
{
var onStateChange: ((BluetoothStateChange) -> Void)?
var onServicesScannedPeripheralsUpdate: ((_ peripherals: [UUID]) -> Void)?
var onCharacteristicsDiscovered: ((_ peripheral: UUID, _ service: CBUUID, _ characteristics: [CBUUID]) -> Void)?
var onCharacteristicWriteFinished: ((_ peripheral: UUID, _ characteristic: CBUUID, _ isSuccessful: Bool) -> Void)?
var onCharacteristicReadFinished: ((_ peripheral: UUID, _ characteristic: CBUUID, _ value: Data?) -> Void)?
private var connectingPeripherals = Set<CBPeripheral>()
private var connectedPeripherals = Set<CBPeripheral>()
private var servicesDiscoveredPeripherals = Set<CBPeripheral>()
private var ignoredPeripherals = Set<CBPeripheral>()
private let central: CBCentralManager
private let logger: LoggerProtocol
var rememberedDeviceUUID: UUID?
init(central: CBCentralManager, logger: LoggerProtocol, rememberedDeviceUUID: UUID? = nil)
{
self.central = central
self.logger = logger
self.rememberedDeviceUUID = rememberedDeviceUUID
super.init()
central.delegate = self
}
func ignore(_ uuid: UUID)
{
guard
let peripheral = connectedPeripherals.first(where: { $0.identifier == uuid })
?? servicesDiscoveredPeripherals.first(where: { $0.identifier == uuid })
else {
return
}
ignoredPeripherals.insert(peripheral)
servicesDiscoveredPeripherals.remove(peripheral)
central.cancelPeripheralConnection(peripheral)
}
func services(for uuid: UUID) -> [CBUUID]
{
return servicesDiscoveredPeripherals.first { $0.identifier == uuid }?.services?.map { $0.uuid } ?? []
}
func discoverCharacteristics(for peripheralUuid: UUID, service uuid: CBUUID)
{
guard
let peripheral = servicesDiscoveredPeripherals.first(where: { $0.identifier == peripheralUuid }),
let service = peripheral.service(with: uuid)
else {
return
}
peripheral.discoverCharacteristics(nil, for: service)
}
func write(
to peripheralUuid: UUID,
service serviceUuid: CBUUID,
characteristic characteristicUuid: CBUUID,
value: Data,
type: CBCharacteristicWriteType
){
guard
let peripheral = servicesDiscoveredPeripherals.first(where: { $0.identifier == peripheralUuid }),
let service = peripheral.service(with: serviceUuid),
let characteristic = service.characteristics?.first(where: { $0.uuid == characteristicUuid })
else {
return
}
peripheral.writeValue(value, for: characteristic, type: type)
}
func read(from peripheralUuid: UUID, service serviceUuid: CBUUID, characteristic characteristicUuid: CBUUID)
{
guard
let peripheral = servicesDiscoveredPeripherals.first(where: { $0.identifier == peripheralUuid }),
let service = peripheral.service(with: serviceUuid),
let characteristic = service.characteristics?.first(where: { $0.uuid == characteristicUuid })
else {
return
}
peripheral.readValue(for: characteristic)
}
}
extension BluetoothCentralService: CBCentralManagerDelegate
{
func centralManagerDidUpdateState(_ central: CBCentralManager)
{
switch central.state
{
case .resetting:
break
case .unknown:
onStateChange?(.unknown)
case .unsupported:
onStateChange?(.unsupported)
case .unauthorized:
onStateChange?(.unauthorized)
case .poweredOff:
onStateChange?(.poweredOff)
connectedPeripherals = []
servicesDiscoveredPeripherals = []
ignoredPeripherals = []
onServicesScannedPeripheralsUpdate?([])
case .poweredOn:
scanRemembered()
default:
logger.log(.warning, "\(#function): Unhandled state type.")
}
}
private func scanRemembered()
{
guard
let uuid = rememberedDeviceUUID,
let peripheral = central.retrievePeripherals(withIdentifiers: [uuid]).first
else {
scanConnected(); return
}
connect(peripheral)
}
private func scanConnected()
{
let connected = central.retrieveConnectedPeripherals(withServices: [])
connectedPeripherals.formUnion(connected)
connectedPeripherals.forEach { $0.discoverServices(nil) }
scanNew()
}
private func scanNew()
{
central.scanForPeripherals(withServices: nil)
}
private func connect(_ peripheral: CBPeripheral)
{
guard
!ignoredPeripherals.contains(peripheral),
!connectingPeripherals.contains(peripheral),
!connectedPeripherals.contains(peripheral),
!servicesDiscoveredPeripherals.contains(peripheral)
else {
return
}
connectingPeripherals.insert(peripheral)
peripheral.delegate = self
central.connect(peripheral)
}
func centralManager(
_ central: CBCentralManager,
didDiscover peripheral: CBPeripheral,
advertisementData: [String : Any],
rssi RSSI: NSNumber
){
guard
!ignoredPeripherals.contains(peripheral),
!connectingPeripherals.contains(peripheral),
!connectedPeripherals.contains(peripheral),
!servicesDiscoveredPeripherals.contains(peripheral)
else {
return
}
connect(peripheral)
}
func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral)
{
connectingPeripherals.remove(peripheral)
connectedPeripherals.insert(peripheral)
peripheral.discoverServices(nil)
}
func centralManager(_ central: CBCentralManager, didDisconnectPeripheral peripheral: CBPeripheral, error: Error?)
{
connectedPeripherals.remove(peripheral)
}
}
extension BluetoothCentralService: CBPeripheralDelegate
{
func peripheral(_ peripheral: CBPeripheral, didDiscoverServices error: Error?)
{
guard error == nil else { return }
servicesDiscoveredPeripherals.insert(peripheral)
connectedPeripherals.remove(peripheral)
onServicesScannedPeripheralsUpdate?(servicesDiscoveredPeripherals.map { $0.identifier })
}
func peripheral(_ peripheral: CBPeripheral, didDiscoverCharacteristicsFor service: CBService, error: Error?)
{
onCharacteristicsDiscovered?(
peripheral.identifier,
service.uuid,
service.characteristics?.compactMap { $0.uuid } ?? []
)
}
func peripheral(_ peripheral: CBPeripheral, didWriteValueFor characteristic: CBCharacteristic, error: Error?)
{
onCharacteristicWriteFinished?(peripheral.identifier, characteristic.uuid, error == nil)
}
func peripheral(_ peripheral: CBPeripheral, didUpdateValueFor characteristic: CBCharacteristic, error: Error?)
{
onCharacteristicReadFinished?(peripheral.identifier, characteristic.uuid, characteristic.value)
}
func peripheral(_ peripheral: CBPeripheral, didModifyServices invalidatedServices: [CBService])
{
// This never gets called if it's actually implemented here!
}
}

Use Bluetooth to control Arduino from IOS app

I've receive my arduino BLE module : SH-HC-08 I now how to use it regarding Android code. I also succeeded to communicate from an IOS app to my arduino by using an app from the app store. Now I would like to create my own app to control my arduino project.
I've been already trying a lot of tutorial available on the web but nothing work ...
But this one look like to be good : Tuto that I follow
To work my Arduino need to receive this value as string :
"0" -> Place the Servo in positon 0
"180" -> Place the Servo in position 180
Here is my arduino code :
in void setup()
bluetoothSerial.begin(9600);
Serial.begin(9600);
pinMode(LED_PIN, OUTPUT);
Serial.println("PrĂȘt");
bluetoothSerial.setTimeout(300);
servo.attach(7, 0, 180);
servo.write(0);
in my void loop()
if(bluetoothSerial.available()){
c = bluetoothSerial.readString();
Serial.println(c);
if(c=="0"){
servo.write(0);
}
if(c=="180"){
servo.write(180);
}
}
By using the Appstore BLE communication app this works very well !
Now with my app nothing happens when I send "180" or "0" ...
My iOS Code :
In the mainViewController :
import UIKit
import CoreBluetooth
class MainViewController: UIViewController, CBCentralManagerDelegate, CBPeripheralDelegate {
var manager:CBCentralManager? = nil
var mainPeripheral:CBPeripheral? = nil
var mainCharacteristic:CBCharacteristic? = nil
let BLEService = "DFB0"
let BLECharacteristic = "DFB1"
#IBOutlet weak var recievedMessageText: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
manager = CBCentralManager(delegate: self, queue: nil);
customiseNavigationBar()
}
// ................... CustomiseNavigationBar() were here
let rightBarButton = UIBarButtonItem()
rightBarButton.customView = rightButton
self.navigationItem.rightBarButtonItem = rightBarButton
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if (segue.identifier == "scan-segue") {
let scanController : ScanTableViewController = segue.destination as! ScanTableViewController
//set the manager's delegate to the scan view so it can call relevant connection methods
manager?.delegate = scanController
scanController.manager = manager
scanController.parentView = self
}
}
// MARK: Button Methods
#objc func scanButtonPressed() {
performSegue(withIdentifier: "scan-segue", sender: nil)
}
#objc func disconnectButtonPressed() {
//this will call didDisconnectPeripheral, but if any other apps are using the device it will not immediately disconnect
manager?.cancelPeripheralConnection(mainPeripheral!)
}
#IBAction func sendButtonPressed(_ sender: AnyObject) {
let helloWorld = "180"
let dataToSend = helloWorld.data(using: String.Encoding.utf8)
if (mainPeripheral != nil) {
mainPeripheral?.writeValue(dataToSend!, for: mainCharacteristic!, type: CBCharacteristicWriteType.withResponse)
print(dataToSend)
} else {
print("haven't discovered device yet")
}
}
// MARK: - CBCentralManagerDelegate Methods
func centralManager(_ central: CBCentralManager, didDisconnectPeripheral peripheral: CBPeripheral, error: Error?) {
mainPeripheral = nil
customiseNavigationBar()
print("Disconnected" + peripheral.name!)
}
func centralManagerDidUpdateState(_ central: CBCentralManager) {
print(central.state)
}
// MARK: CBPeripheralDelegate Methods
func peripheral(_ peripheral: CBPeripheral, didDiscoverServices error: Error?) {
for service in peripheral.services! {
print("Service found with UUID: " + service.uuid.uuidString)
//device information service
if (service.uuid.uuidString == "180A") {
peripheral.discoverCharacteristics(nil, for: service)
}
//GAP (Generic Access Profile) for Device Name
// This replaces the deprecated CBUUIDGenericAccessProfileString
if (service.uuid.uuidString == "1800") {
peripheral.discoverCharacteristics(nil, for: service)
}
//Bluno Service
if (service.uuid.uuidString == BLEService) {
peripheral.discoverCharacteristics(nil, for: service)
}
}
}
func peripheral(_ peripheral: CBPeripheral, didDiscoverCharacteristicsFor service: CBService, error: Error?) {
//get device name
if (service.uuid.uuidString == "1800") {
for characteristic in service.characteristics! {
if (characteristic.uuid.uuidString == "2A00") {
peripheral.readValue(for: characteristic)
print("Found Device Name Characteristic")
}
}
}
if (service.uuid.uuidString == "180A") {
for characteristic in service.characteristics! {
if (characteristic.uuid.uuidString == "2A29") {
peripheral.readValue(for: characteristic)
print("Found a Device Manufacturer Name Characteristic")
mainCharacteristic = characteristic
} else if (characteristic.uuid.uuidString == "2A23") {
peripheral.readValue(for: characteristic)
print("Found System ID")
mainCharacteristic = characteristic
}
}
}
if (service.uuid.uuidString == BLEService) {
for characteristic in service.characteristics! {
if (characteristic.uuid.uuidString == BLECharacteristic) {
//we'll save the reference, we need it to write data
mainCharacteristic = characteristic
//Set Notify is useful to read incoming data async
peripheral.setNotifyValue(true, for: characteristic)
print("Found Bluno Data Characteristic")
}
}
}
}
func peripheral(_ peripheral: CBPeripheral, didUpdateValueFor characteristic: CBCharacteristic, error: Error?) {
if (characteristic.uuid.uuidString == "2A00") {
//value for device name recieved
let deviceName = characteristic.value
print(deviceName ?? "No Device Name")
} else if (characteristic.uuid.uuidString == "2A29") {
//value for manufacturer name recieved
let manufacturerName = characteristic.value
print(manufacturerName ?? "No Manufacturer Name")
} else if (characteristic.uuid.uuidString == "2A23") {
//value for system ID recieved
let systemID = characteristic.value
print(systemID ?? "No System ID")
} else if (characteristic.uuid.uuidString == BLECharacteristic) {
//data recieved
if(characteristic.value != nil) {
let stringValue = String(data: characteristic.value!, encoding: String.Encoding.utf8)!
recievedMessageText.text = stringValue
}
}
}
}
And my ScanTableViewController :
import UIKit
import CoreBluetooth
class ScanTableViewController: UITableViewController, CBCentralManagerDelegate {
var peripherals:[CBPeripheral] = []
var manager:CBCentralManager? = nil
var parentView:MainViewController? = nil
override func viewDidLoad() {
super.viewDidLoad()
}
override func viewDidAppear(_ animated: Bool) {
scanBLEDevices()
}
// MARK: - Table view data source
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of rows
return peripherals.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "scanTableCell", for: indexPath)
let peripheral = peripherals[indexPath.row]
cell.textLabel?.text = peripheral.name
return cell
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let peripheral = peripherals[indexPath.row]
manager?.connect(peripheral, options: nil)
}
// MARK: BLE Scanning
func scanBLEDevices() {
//manager?.scanForPeripherals(withServices: [CBUUID.init(string: parentView!.BLEService)], options: nil)
//if you pass nil in the first parameter, then scanForPeriperals will look for any devices.
manager?.scanForPeripherals(withServices: nil, options: nil)
//stop scanning after 3 seconds
DispatchQueue.main.asyncAfter(deadline: .now() + 3.0) {
self.stopScanForBLEDevices()
}
}
func stopScanForBLEDevices() {
manager?.stopScan()
}
// MARK: - CBCentralManagerDelegate Methods
func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber) {
if(!peripherals.contains(peripheral)) {
peripherals.append(peripheral)
}
self.tableView.reloadData()
}
func centralManagerDidUpdateState(_ central: CBCentralManager) {
print(central.state)
}
func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) {
//pass reference to connected peripheral to parent view
parentView?.mainPeripheral = peripheral
peripheral.delegate = parentView
peripheral.discoverServices(nil)
//peripheral.discoverCharacteristics(<#T##characteristicUUIDs: [CBUUID]?##[CBUUID]?#>, for: <#T##CBService#>)
//set the manager's delegate view to parent so it can call relevant disconnect methods
manager?.delegate = parentView
parentView?.customiseNavigationBar()
if let navController = self.navigationController {
navController.popViewController(animated: true)
}
print("Connected to " + peripheral.name!)
}
func centralManager(_ central: CBCentralManager, didFailToConnect peripheral: CBPeripheral, error: Error?) {
print(error!)
}
}
I'm sorry about put a lot of code it isn't so clean but I totally don't know where is the problem ...
Thanks a lot for your help !

How to modify an existing BLECentral class into a singleton class?

Hi I'm trying to make the BLE Central class into a Singleton class?
I'm running into a few crashes while trying to implement it.
Here is my code:
//This is the BLE Central Class
import Foundation
import UIKit
import CoreBluetooth
var txCharacteristic : CBCharacteristic?
var rxCharacteristic : CBCharacteristic?
var blePeripheral : CBPeripheral?
var characteristicASCIIValue = NSString()
class BLECentralViewController : UIViewController, CBCentralManagerDelegate, CBPeripheralDelegate, UITableViewDelegate, UITableViewDataSource{
//Data
var centralManager : CBCentralManager!
var RSSIs = [NSNumber]()
var data = NSMutableData()
var writeData: String = ""
var peripherals: [CBPeripheral] = []
var characteristicValue = [CBUUID: NSData]()
var timer = Timer()
var characteristics = [String : CBCharacteristic]()
//UI
#IBOutlet weak var baseTableView: UITableView!
#IBOutlet weak var refreshButton: UIBarButtonItem!
#IBAction func refreshAction(_ sender: AnyObject) {
disconnectFromDevice()
self.peripherals = []
self.RSSIs = []
self.baseTableView.reloadData()
startScan()
}
override func viewDidLoad() {
super.viewDidLoad()
self.baseTableView.delegate = self
self.baseTableView.dataSource = self
self.baseTableView.reloadData()
centralManager = CBCentralManager(delegate: self, queue: nil)
let backButton = UIBarButtonItem(title: "Disconnect", style: .plain, target: nil, action: nil)
navigationItem.backBarButtonItem = backButton
}
override func viewDidAppear(_ animated: Bool) {
disconnectFromDevice()
super.viewDidAppear(animated)
refreshScanView()
print("View Cleared")
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
print("Stop Scanning")
centralManager?.stopScan()
}
/*Okay, now that we have our CBCentalManager up and running, it's time to start searching for devices. You can do this by calling the "scanForPeripherals" method.*/
func startScan() {
peripherals = []
print("Now Scanning...")
self.timer.invalidate()
centralManager?.scanForPeripherals(withServices: [BLEService_UUID] , options: [CBCentralManagerScanOptionAllowDuplicatesKey:false])
Timer.scheduledTimer(timeInterval: 17, target: self, selector: #selector(self.cancelScan), userInfo: nil, repeats: false)
}
/*We also need to stop scanning at some point so we'll also create a function that calls "stopScan"*/
func cancelScan() {
self.centralManager?.stopScan()
print("Scan Stopped")
print("Number of Peripherals Found: \(peripherals.count)")
}
func refreshScanView() {
baseTableView.reloadData()
}
//-Terminate all Peripheral Connection
/*
Call this when things either go wrong, or you're done with the connection.
This cancels any subscriptions if there are any, or straight disconnects if not.
(didUpdateNotificationStateForCharacteristic will cancel the connection if a subscription is involved)
*/
func disconnectFromDevice () {
if blePeripheral != nil {
// We have a connection to the device but we are not subscribed to the Transfer Characteristic for some reason.
// Therefore, we will just disconnect from the peripheral
centralManager?.cancelPeripheralConnection(blePeripheral!)
}
}
func restoreCentralManager() {
//Restores Central Manager delegate if something went wrong
centralManager?.delegate = self
}
func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral,advertisementData: [String : Any], rssi RSSI: NSNumber) {
blePeripheral = peripheral
self.peripherals.append(peripheral)
self.RSSIs.append(RSSI)
peripheral.delegate = self
self.baseTableView.reloadData()
if blePeripheral == nil {
print("Found new pheripheral devices with services")
print("Peripheral name: \(String(describing: peripheral.name))")
print("**********************************")
print ("Advertisement Data : \(advertisementData)")
}
}
//Peripheral Connections: Connecting, Connected, Disconnected
//-Connection
func connectToDevice () {
centralManager?.connect(blePeripheral!, options: nil)
}
//-Connected
func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) {
print("*****************************")
print("Connection complete")
print("Peripheral info: \(String(describing: blePeripheral))")
//Stop Scan- We don't need to scan once we've connected to a peripheral. We got what we came for.
centralManager?.stopScan()
print("Scan Stopped")
//Erase data that we might have
data.length = 0
//Discovery callback
peripheral.delegate = self
//Only look for services that matches transmit uuid
peripheral.discoverServices([BLEService_UUID])
//Once connected, move to new view controller to manager incoming and outgoing data
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let firstVC = storyboard.instantiateViewController(withIdentifier: "FirstViewController") as! FirstViewController
firstVC.peripheral = peripheral
navigationController?.pushViewController(firstVC, animated: true)
}
func centralManager(_ central: CBCentralManager, didFailToConnect peripheral: CBPeripheral, error: Error?) {
if error != nil {
print("Failed to connect to peripheral")
return
}
}
func disconnectAllConnection() {
centralManager.cancelPeripheralConnection(blePeripheral!)
}
func peripheral(_ peripheral: CBPeripheral, didDiscoverServices error: Error?) {
print("*******************************************************")
if ((error) != nil) {
print("Error discovering services: \(error!.localizedDescription)")
return
}
guard let services = peripheral.services else {
return
}
//We need to discover the all characteristic
for service in services {
peripheral.discoverCharacteristics(nil, for: service)
// bleService = service
}
print("Discovered Services: \(services)")
}
func peripheral(_ peripheral: CBPeripheral, didDiscoverCharacteristicsFor service: CBService, error: Error?) {
print("*******************************************************")
if ((error) != nil) {
print("Error discovering services: \(error!.localizedDescription)")
return
}
guard let characteristics = service.characteristics else {
return
}
print("Found \(characteristics.count) characteristics!")
for characteristic in characteristics {
//looks for the right characteristic
if characteristic.uuid.isEqual(BLE_Characteristic_uuid_Rx) {
rxCharacteristic = characteristic
//Once found, subscribe to the this particular characteristic...
peripheral.setNotifyValue(true, for: rxCharacteristic!)
// We can return after calling CBPeripheral.setNotifyValue because CBPeripheralDelegate's
// didUpdateNotificationStateForCharacteristic method will be called automatically
peripheral.readValue(for: characteristic)
print("Rx Characteristic: \(characteristic.uuid)")
}
if characteristic.uuid.isEqual(BLE_Characteristic_uuid_Tx){
txCharacteristic = characteristic
print("Tx Characteristic: \(characteristic.uuid)")
}
peripheral.discoverDescriptors(for: characteristic)
}
}
func peripheral(_ peripheral: CBPeripheral, didUpdateValueFor characteristic: CBCharacteristic, error: Error?) {
if characteristic == rxCharacteristic {
if let ASCIIstring = NSString(data: characteristic.value!, encoding: String.Encoding.utf8.rawValue) {
characteristicASCIIValue = ASCIIstring
print("Value Recieved: \((characteristicASCIIValue as String))")
NotificationCenter.default.post(name:NSNotification.Name(rawValue: "Notify"), object: nil)
}
}
}
func peripheral(_ peripheral: CBPeripheral, didDiscoverDescriptorsFor characteristic: CBCharacteristic, error: Error?) {
print("*******************************************************")
if error != nil {
print("\(error.debugDescription)")
return
}
if ((characteristic.descriptors) != nil) {
for x in characteristic.descriptors!{
let descript = x as CBDescriptor!
print("function name: DidDiscoverDescriptorForChar \(String(describing: descript?.description))")
print("Rx Value \(String(describing: rxCharacteristic?.value))")
print("Tx Value \(String(describing: txCharacteristic?.value))")
}
}
}
func peripheral(_ peripheral: CBPeripheral, didUpdateNotificationStateFor characteristic: CBCharacteristic, error: Error?) {
print("*******************************************************")
if (error != nil) {
print("Error changing notification state:\(String(describing: error?.localizedDescription))")
} else {
print("Characteristic's value subscribed")
}
if (characteristic.isNotifying) {
print ("Subscribed. Notification has begun for: \(characteristic.uuid)")
}
}
func centralManager(_ central: CBCentralManager, didDisconnectPeripheral peripheral: CBPeripheral, error: Error?) {
print("Disconnected")
}
func peripheral(_ peripheral: CBPeripheral, didWriteValueFor characteristic: CBCharacteristic, error: Error?) {
guard error == nil else {
print("Error discovering services: error")
return
}
print("Message sent")
}
func peripheral(_ peripheral: CBPeripheral, didWriteValueFor descriptor: CBDescriptor, error: Error?) {
guard error == nil else {
print("Error discovering services: error")
return
}
print("Succeeded!")
}
//Table View Functions
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.peripherals.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "BlueCell") as! PeripheralTableViewCell
let peripheral = self.peripherals[indexPath.row]
let RSSI = self.RSSIs[indexPath.row]
if peripheral.name == nil {
cell.peripheralLabel.text = "nil"
} else {
cell.peripheralLabel.text = peripheral.name
}
cell.rssiLabel.text = "RSSI: \(RSSI)"
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
blePeripheral = peripherals[indexPath.row]
connectToDevice()
}
func centralManagerDidUpdateState(_ central: CBCentralManager) {
if central.state == CBManagerState.poweredOn {
// We will just handle it the easy way here: if Bluetooth is on, proceed...start scan!
print("Bluetooth Enabled")
startScan()
} else {
//If Bluetooth is off, display a UI alert message saying "Bluetooth is not enable" and "Make sure that your bluetooth is turned on"
print("Bluetooth Disabled- Make sure your Bluetooth is turned on")
let alertVC = UIAlertController(title: "Bluetooth is not enabled", message: "Make sure that your bluetooth is turned on", preferredStyle: UIAlertControllerStyle.alert)
let action = UIAlertAction(title: "ok", style: UIAlertActionStyle.default, handler: { (action: UIAlertAction) -> Void in
self.dismiss(animated: true, completion: nil)
})
alertVC.addAction(action)
self.present(alertVC, animated: true, completion: nil)
}
}
}
My questions are:
How can I modify the BLECentral class to use as a singleton so I
can call from any view controller class to read and write data?
Can I simply make the first view controller as a singleton instead of the BLE central and read/write by calling this from other view controller class?
Or can I extend the first view controller class scope by using
extension?
I'm currently able to read/write data but peripheral doesn't seem to
be called properly sometimes, therefore gets disconnected? Any
suggestions/fixes?
Here is my FirstViewController class:
class FirstViewController: UIViewController, UIPeripheralManagerDelegate {
var peripheralManager: CBPeripheralManager?
var peripheral: CBPeripheral!
viewDidLoad(){
//I'm calling the blePeripheral from BLE class to the peripheral in the current class
peripheral = blePeripheral
}
//I have a button here to send some data and only when I receive the data I want to go to the next view controller
#IBAction func login(_sender: AnyObject) {
//This is my write code
let bytes : [UInt8] = [ 0x1A, 0x2B, 0x3C, 0x4D ]
let Transmitdata = NSData(bytes: bytes, length: bytes.count)
peripheral.writeValue(Transmitdata as Data, for: txCharacteristic!, type: CBCharacteristicWriteType.withoutResponse)
print("Data Sent",Transmitdata)
//Give time for data to be received fromdevice
sleep(1)
//let ReceiveData = rxCharacteristic?.value
if let ReceiveData = ReceiveData {
let ReceivedNoOfBytes = ReceiveData.count
var ReceivedByteArray = [UInt8](repeating: 0, count: ReceivedNoOfBytes)
(ReceiveData as NSData).getBytes(&ReceivedByteArray, length: ReceivedNoOfBytes)
print("Data Received ",ReceivedByteArray)
//checking if we received the right data?
if(ReceivedByteArray[0] == 10 && ReceivedByteArray[1] == 20 && ReceivedByteArray[2] == 30 && ReceivedByteArray[3] == 40){
performSegue(withIdentifier: "Second_View", sender: self)
}
}
}
And the SecondViewController class:
class SecondViewController: UIViewController{
var firstview: FirstViewController?
var peripheralManager: CBPeripheralManager?
var peripheral: CBPeripheral!
override func viewWillAppear(_animated: Bool){
let peripheral = firstview?.peripheral
let peripheralManager = firstview?.peripheralManager
}
//I have another button here to direct me to third view controller class
#IBAction func mainmenu(_sender: AnyObject){
//send some bytes
//receiver some bytes
//similar to the first view controller
If correct data is received
{
performSegue(withIdentifier: "Main_M", sender: self)
}
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?){
if segue.destination is Main_M
{
let gotoM = segue.destination as? Main_M
gotoM?.peripheral = firstview?.peripheral
}
}

iOS 11 Core Bluetooth restoration not working

I have an iOS app that uses Core Bluetooth to connect to a V.BTTN smart button. Everything worked perfectly fine in iOS 10, but since iOS 11 has come out the restoration process seems to break.
When I launch my app, with a previously paired button, the OS does in fact call the centralManager:willRestoreState, and the accompanying dictionary includes a pointer to a CBPeripheral object that has a status of connected. Just as it did back in iOS 10. However, the problem I am running into is when I call the discoverServices on the peripheral I am never returned any services in the peripheral:didDiscoverServices method. In fact that method, nor any other method, is called at all.
I have been searching all of the internet and have found people having similar issues with button pairing an connections, but those have generally been issues with improper lifecycle management of the peripheral object. I believe I have everything setup correct and at a loss. Does anyone have any idea what could be going on here?
import Foundation
import CoreBluetooth
class SmartButtonManager: NSObject {
//MARK: - Singleton
static let sharedManager = SmartButtonManager()
//MARK: - Properties
var discoveredDevices: [CBPeripheral] {
get {
return perfs
}
}
fileprivate(set) var isBluetoothOn = false
//MARK: - Private Constants & Variables
fileprivate var connectedButtonUUID: String?
fileprivate let queue = DispatchQueue(label: "V.BTTN", qos: .background, attributes: .concurrent, autoreleaseFrequency: .inherit, target: nil)
fileprivate var manager: CBCentralManager?
fileprivate var perfs = [CBPeripheral]()
fileprivate var connectedPerf: CBPeripheral?
fileprivate var isButtonReady = false
//MARK: - Initialization
override init() {
super.init()
}
//MARK: - Configure
func configure(withLaunchOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) {
// create new central manager
manager = CBCentralManager(delegate: self, queue: queue, options: [CBCentralManagerOptionRestoreIdentifierKey: managerIdentifier])
}
}
//MARK: - V.BTTN
extension SmartButtonManager: CBCentralManagerDelegate, CBPeripheralDelegate {
func scanForVbttn() {
perfs.removeAll()
manager?.scanForPeripherals(withServices: services, options: nil)
}
func centralManagerDidUpdateState(_ central: CBCentralManager) {
switch central.state {
case .poweredOff:
print("[centralManagerDidUpdateState] CB BLE hardware is powered off")
perfs.removeAll()
isBluetoothOn = false
case .poweredOn:
print("[centralManagerDidUpdateState] CB BLE hardware is powered on. Start scanning for peripherals")
isBluetoothOn = true
case .unauthorized:
print("[centralManagerDidUpdateState] CB BLE hardware is not authorized")
case .unsupported:
print("[centralManagerDidUpdateState] CB BLE hardware is not supported")
isBluetoothOn = false
default:
print("[centralManagerDidUpdateState] CB BLE hardware state is unknown")
}
}
func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber) {
print("[centralManager:didDiscover peripheral:advertisementData] CB BLE did discover peripheral with advertisement data: \(advertisementData)")
guard let perfName = advertisementData[CBAdvertisementDataLocalNameKey] as? String else {
print("[centralManager:didDiscover peripheral:advertisementData] peripheral name is unknown")
return
}
if perfName.contains("V.ALRT") {
peripheral.delegate = self
perfs.append(peripheral)
if connectedButtonUUID == perfName {
connect(peripheral: peripheral)
}
}
}
func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) {
print("[central:didConnect peripheral:] CB BLE hardware did connect")
handleDidConnect(toPeripheral: peripheral)
}
func centralManager(_ central: CBCentralManager, didFailToConnect peripheral: CBPeripheral, error: Error?) {
print("[central:didFailToConnect error:] CB BLE peripheral did failed to connect with error: \(String(describing: error))")
connectedPerf = nil
isButtonReady = false
connectedButtonUUID = nil
}
func centralManager(_ central: CBCentralManager, didDisconnectPeripheral peripheral: CBPeripheral, error: Error?) {
print("[central:didDisconnectPeripheral peripheral:] CB BLE peripheral did disconnect")
connectedPerf = nil
isButtonReady = false
connectedButtonUUID = nil
}
func centralManager(_ central: CBCentralManager, willRestoreState dict: [String : Any]) {
print("[central:willRestoreState dict:] CB BLE hardware will restore state")
print("\(dict)")
guard let ps = dict[CBCentralManagerRestoredStatePeripheralsKey] as? [CBPeripheral] else {
print("[central:willRestoreState dict:] No perfs to restore")
return
}
print("[central:willRestoreState dict:] Will restore perfs")
perfs = ps
print("[central:willRestoreState dict:] Attempt to reconnect to V.BTTN")
print("[central:willRestoreState dict:] perfs \(perfs)")
for p in perfs {
if p.name == connectedButtonUUID {
print("[central:willRestoreState dict:] Connect to perf \(p)")
handleDidConnect(toPeripheral: p)
break
}
}
}
func peripheral(_ peripheral: CBPeripheral, didDiscoverServices error: Error?) {
guard let services = peripheral.services else {
print("[peripheral:didDiscoverServices error:] CB BLE peripheral unable to discover services")
return
}
print("[peripheral:didDiscoverServices error:] BLE peripheral did discover services")
for s in services {
print("[peripheral:didDiscoverServices error:] CB BLE Service \(s.description)")
peripheral.discoverCharacteristics(nil, for: s)
}
}
func peripheral(_ peripheral: CBPeripheral, didDiscoverCharacteristicsFor service: CBService, error: Error?) {
print("[peripheral:didDiscoverCharacteristicsFor service:] CB BLE did discover characteristics for service \(service.uuid.description)")
if compareCBUUID(uuid1: service.uuid, uuid2: CBUUID(string: BLE_VSN_GATT_SERVICE_UUID)) {
guard let characteristics = service.characteristics else {
return
}
for aChar in characteristics {
// write the verification key
if aChar.uuid.isEqual(CBUUID(string: BLE_VERIFICATION_SERVICE_UUID)) {
self.writeVerificationKey(forPeripheral: peripheral, characteristic: aChar)
self.enable(peripheral: peripheral)
break
}
}
}
}
func peripheral(_ peripheral: CBPeripheral, didUpdateValueFor characteristic: CBCharacteristic, error: Error?) {
//NOTE: This code has been omitted as there is little need to see this
}
func peripheral(_ peripheral: CBPeripheral, didWriteValueFor characteristic: CBCharacteristic, error: Error?) {
print("[peripheral:didWriteValueFor characteristic:] characteristic: \(characteristic.uuid)")
if let e = error {
print("[peripheral:didWriteValueFor characteristic:] error: \(e)")
}
}
func peripheral(_ peripheral: CBPeripheral, didUpdateNotificationStateFor characteristic: CBCharacteristic, error: Error?) {
if !characteristic.isNotifying {
print("[peripheral:didUpdateNotificationStateFor:][Characteristic is not notifiying so cancel the connection]")
manager?.cancelPeripheralConnection(peripheral)
}
}
//MARK: - Helpers
fileprivate func writeVerificationKey(forPeripheral peripheral: CBPeripheral, characteristic: CBCharacteristic) {
print("[peripheral:didDiscoverCharacteristicsFor service:] Write verification key")
let data = NSData(bytes: [0x80,0xBE,0xF5,0xAC,0xFF] as [UInt8], length: 5)
peripheral.writeValue(data as Data, for: characteristic, type: CBCharacteristicWriteType.withResponse)
}
fileprivate func handleDidConnect(toPeripheral peripheral: CBPeripheral) {
if let n = peripheral.name {
connectedButtonUUID = n
}
connectedPerf = peripheral
peripheral.delegate = self
peripheral.discoverServices(nil)
isButtonReady = true
}
fileprivate func enable(peripheral: CBPeripheral) {
guard let services = peripheral.services else {
return
}
for service: CBService in services {
if compareCBUUID(uuid1: service.uuid, uuid2: CBUUID(string: BLE_VSN_GATT_SERVICE_UUID)) {
guard let characteristics = service.characteristics else {
return
}
for aChar in characteristics {
if aChar.uuid.isEqual(CBUUID(string: BLE_KEYPRESS_DETECTION_UUID)) {
// enable button
print("[peripheral:didDiscoverCharacteristicsFor service:] Enable short press")
let data = NSData(bytes: [0x02] as [UInt8], length: 1)
peripheral.writeValue(data as Data, for: aChar, type: CBCharacteristicWriteType.withResponse);
} else if aChar.uuid.isEqual(CBUUID(string: BLE_SILENT_NORMAL_MODE)) {
// enable button
print("[peripheral:didDiscoverCharacteristicsFor service:] Enable normal mode")
let data = NSData(bytes: [0x00] as [UInt8], length: 1)
peripheral.writeValue(data as Data, for: aChar, type: CBCharacteristicWriteType.withResponse);
} else if aChar.uuid.isEqual(CBUUID(string: BLE_FALL_KEYPRESS_DETECTION_UUID)) {
// enable fall detection
print("[peripheral:didDiscoverCharacteristicsFor service:] Enable fall detection")
peripheral.setNotifyValue(true, for: aChar)
}
}
}
}
checkBatteryLevel()
}
func disconnectVbttn() {
guard let peripheral = connectedPerf else {
return
}
setVbttnToStealthMode()
manager?.cancelPeripheralConnection(peripheral)
isButtonReady = false
}
fileprivate func compareCBUUID(uuid1: CBUUID, uuid2: CBUUID) -> Bool {
if (uuid1.data as NSData).isEqual(to: uuid2.data) {
return true
}
return false
}
func stopScanning() {
manager?.stopScan()
}
}

Swift, how to call a function in other viewcontroller?

My program has two controllers, CallerTableViewController, FunctionViewController
Caller is in CallerTableViewController and the function is in FunctionViewController
Now screen is displaying FunctionViewController while the calling program is in CallerTableViewController, the calling program should call the function in FunctionViewController
How can I call the function which is displaying on screen?
Update:
this is actual program
import UIKit
import CoreBluetooth
class TableViewController: UITableViewController,
CBCentralManagerDelegate,
CBPeripheralDelegate {
var centralManager:CBCentralManager!
var connectingPeripheral:CBPeripheral!
var bleDeviceName = [String]()
var bleDevice=[CBPeripheral]()
override func viewDidLoad() {
super.viewDidLoad()
let centralManager = CBCentralManager(delegate: self, queue: nil)
centralManager.scanForPeripherals(withServices: nil, options: nil)
self.centralManager = centralManager;
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
// MARK: - Table view data source
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return bleDevice.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "oneCell", for: indexPath)
cell.textLabel?.text = bleDeviceName[indexPath.row]
return cell
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath){
var peripheral=bleDevice[indexPath.row]
self.centralManager.stopScan()
connectingPeripheral = peripheral
connectingPeripheral.delegate = self
centralManager.connect(connectingPeripheral, options: nil)
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
centralManager = CBCentralManager(delegate: self, queue: DispatchQueue.main)
}
func centralManagerDidUpdateState(_ central: CBCentralManager) {
print("--- centralManagerDidUpdateState")
switch central.state{
case .poweredOn:
let serviceUUIDs:[AnyObject] = [CBUUID(string: "1111")]
let lastPeripherals = centralManager.retrieveConnectedPeripherals(withServices: serviceUUIDs as! [CBUUID])
print(lastPeripherals.count)
if lastPeripherals.count > 0{
print("count>0")
let device = lastPeripherals.last! as CBPeripheral;
connectingPeripheral = device;
centralManager.connect(connectingPeripheral, options: nil)
}
else {
centralManager.scanForPeripherals(withServices:nil, options: nil)
}
case .poweredOff:
print("--- central state is powered off")
case .resetting:
print("--- central state is resetting")
case .unauthorized:
print("--- central state is unauthorized")
case .unknown:
print("--- central state is unknown")
case .unsupported:
print("--- central state is unsupported")
}
}
func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber) {
print("--- didDiscover peripheral")
if let localName = advertisementData[CBAdvertisementDataLocalNameKey] as? String{
bleDevice.append(peripheral)
bleDeviceName.append(localName)
DispatchQueue.main.async{
self.tableView.reloadData()
}
}else{
print("!!!--- can't unwrap advertisementData[CBAdvertisementDataLocalNameKey]")
}
}
func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) {
print("--- didConnectPeripheral")
peripheral.delegate = self
peripheral.discoverServices(nil)
print("--- peripheral state is \(peripheral.state)")
}
func peripheral(_ peripheral: CBPeripheral, didDiscoverServices error: Error?) {
if (error) != nil{
print("!!!--- error in didDiscoverServices: \(error?.localizedDescription)")
}
else {
print("--- error in didDiscoverServices")
for service in peripheral.services as [CBService]!{
print("before disc chara"+service.uuid.uuidString)
if service.uuid.uuidString=="11111111-1111-11111111-1111111111111" {
peripheral.discoverCharacteristics(nil, for: service)
print("disc chara")
}
}
}
}
func peripheral(_ peripheral: CBPeripheral, didDiscoverCharacteristicsFor service: CBService, error: Error?) {
if (error) != nil{
print("!!!--- error in didDiscoverCharacteristicsFor: \(error?.localizedDescription)")
}
else {
print("found charact: service"+service.uuid.uuidString)
if service.uuid == CBUUID(string: "11111111-1111-11111111-1111111111111"){
for characteristic in service.characteristics! as [CBCharacteristic]{
switch characteristic.uuid.uuidString{
case "00000000-0000-0000-0000-0000000000000":
print("Found Characteristic")
peripheral.setNotifyValue(true, for: characteristic)
default:
print()
}
}
}
}
}
func peripheral(_ peripheral: CBPeripheral, didUpdateValueFor characteristic: CBCharacteristic, error: Error?) {
//call function here
//call function here
//call function here
//call function here
//call function here
//call function here
//call function here
//call function here
//call function here
//call function here
//call function here
//call function here
}
}
// this is the function in FunctionViewController
func printTextField() {
print(textField.text)
}
You can try this,
Class from where call back is to send ->
var dismissCallBackBlock: (() -> Void)?
func dismissControllerCallBackBlock(completionBlock:#escaping () ->Void){
dismissCallBackBlock = completionBlock
}
Class where call back is received ->
classObj.dismissControllerCallBackBlock { (Bool) in
}
Hope, it works.
The problem is get the 'FunctionController' object .
You can try this :
let story = UIStoryboard.init(name: "YOUR_STORY_BOARD_NAME", bundle: Bundle.main);
let fvc = story.instantiateViewController(withIdentifier: "YOUR_VIEWCONTROLLER_IDENTIFIER");
fvc.someFunction();
You can find "YOUR_STORY_BOARD_NAME" on your file's list , usually to be "Main":
Choose your 'FunctionViewController' in the storyboard and find YOUR_VIEWCONTROLLER_IDENTIFIER here:

Resources