Pairing issues with IOS9 Beta 5

Hi,


I just installed the new IOS9 Beta 5 version on my iPod (5th generation) and I am now trying to use my BLE application.


Scenario is:

I am able to connect successfully to the other little BLE device then I want to write on an encrypted characteristic. Right after the write command, I have the regular IOS pairing popup then after I entered the correct pairing key I am not receiving any confirmation through 'didWriteValueForCharacteristic' delegate method.


Notes:

This scenario is working fine with IOS8.

This scenario is working fine if I simulate the little BLE device on an IOS device. (I also noticed that pairing procedure between 2 IOS devices was different)


Do you guys know if IOS9 pairing procedure has been changed ? Is there a new protocol to follow ?


Thank you !

Replies

What is the current BLE specification implemented in IOS 9 ?

We are having similar issue with our BLE pairing. I hope Apple engineers are looking at this issue and fix it in GM build or release another beta.

BLE bonding still seems broken in iOS 9 GM Seed. Always get back a CBATTErrorInsufficientEncryption error after attempting to connect a bonded BLE device. Has anyone found a fix?

Everyone, we need as much detailed information about the BLE device exhibiting the issue.

Make, model, firmware version. If you know the details about the BLE module/controller, please post as much information as you can about that as well.

Post them here so others can compare the info with their devices.

Also file a Radar at https://bugreport.apple.com with the same information as soon as possible.

We have this problem with iPhone 6 running iOS 9 connecting to a Ti CC2540 BLE dongle powered device.

This device have worked fine pairing to all phones from 4S to 6...

We see the same issue as well. BLE Pairing with Ipad 3 and BT LE 4.0 Blood Pressure device fails after we try to update notification .

The same works on iOS 9.0 on the iPhone 5s. The error returned is -


Error code was Error Domain=CBATTErrorDomain Code=15 "Encryption is insufficient." UserInfo={NSLocalizedDescription=Encryption is insufficient.}

Still not Working with iOS9.1


Same error

Our setup for this error is:


- the device BLE controller is a nordic N51822

- tested with iPhone A1429 (but fails also on all other iPhones with BLE4.x capabilities)

- iOS Build is 9.1 (13B143) (but also fails with all iOS version from 9.x up, even all the betas)


So what I've done is:


In code i use some constants for convenience:


#define findMeServiceUUID            [CBUUID UUIDWithString:@"1802"]
#define genericAccessServiceUUID      [CBUUID UUIDWithString:@"1800"]
#define linkLossServiceUUID          [CBUUID UUIDWithString:@"1803"]
#define deviceNameCharacteristicUUID  [CBUUID UUIDWithString:@"2A00"]
#define alertLevelCharacteristicUUID  [CBUUID UUIDWithString:@"2A06"]
#define BT_ALERT_LEVEL_NONE 0
#define BT_LEVEL_MILD 1
#define BT_ALERT_LEVEL_HIGH 2
#define BT_ALERT_LEVEL_RESERVED(LVL) LVL


1. Scan for peripherals with findMe and linkLoss Service (1802 and 1803):


  NSDictionary* scanOptions = [NSDictionary dictionaryWithObject:[NSNumber numberWithBool:NO]
                                                          forKey:CBCentralManagerScanOptionAllowDuplicatesKey];
  NSArray* serviceArray = [NSArray arrayWithObjects:findMeServiceUUID,linkLossServiceUUID, nil];
  [centralManager scanForPeripheralsWithServices:serviceArray options:scanOptions];


2. When found an peripheral i add the CBPeripheral* to an mutable array used as datasource for a table view displaying the scan results:


- (void) centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI
{
  NSLog(@"INFO: Did discover peripheral <%@> with identifier <%@>", peripheral.name, peripheral.identifier);
  [peripherals addObject:peripheral];
  // Update UITableView
  [self reloadTable];
}


3. Selected the peripheral in table view (set as CBPeripheral* selectedPeripheral) and connected to it with:


  NSDictionary* connectOptions = [NSDictionary dictionaryWithObject:[NSNumber numberWithBool:YES]
                                                            forKey:CBConnectPeripheralOptionNotifyOnDisconnectionKey];
  [centralManager connectPeripheral:selectedPeripheral options:connectOptions];


4. When connected I start the service discovery


- (void) centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral
{
  NSLog(@"INFO: Did connect to peripheral <%@> with identifier <%@>", peripheral.name, peripheral.identifier);
  isConnected = YES;
  // Update the info UILabel
  [self updateLabel];
  // Start service discovery
  [peripheral discoverServices:nil];
}


5. When a service is discoverd i start to discover the service characteristics:


- (void) peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error
{
  NSLog(@"INFO: Did discover %d services on %@", (int)[peripheral services].count, [peripheral name]);
  for(CBService *s in [peripheral services]) {
    if([[s UUID] isEqual:findMeServiceUUID])
      immediateAlertService = s;
    if([[s UUID] isEqual:linkLossServiceUUID])
      linkLossService = s;
    NSLog(@"INFO: Did discover service %@ on %@", [s.UUID representativeString], [peripheral name]);
    [peripheral discoverCharacteristics:[NSArray arrayWithObject:alertLevelCharacteristicUUID] forService:s];
  }
}


6. When discoverd a characterisics for a service i store thr references to a variable.


- (void) peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error
{
  NSLog(@"INFO: Did discover %d characteristics for service %@ on peripheral %@", (int)service.characteristics.count, service, peripheral);
  for(CBCharacteristic *c in [service characteristics])
  {
    NSLog(@"INFO: Did discover characteristic %@ for service %@ on peripheral %@", [c.UUID representativeString], service, peripheral);
    if([service isEqual:immediateAlertService] &&
      [[c UUID] isEqual:alertLevelCharacteristicUUID])
      immediateAlertAlertLevelCharacteristic = c;
    else if([service isEqual:linkLossService] &&
            [[c UUID] isEqual:alertLevelCharacteristicUUID]) {
      if(isBonded)
        return;
      linkLossAlertLevelCharacteristic = c;
      if(linkLossAlertLevelCharacteristic)
        [self writeLinkLossAlert:BT_ALERT_LEVEL_NONE];
    }
  }
}


7. As you can see if linkLossAlertLevelCharacteristic is discovered i immediately write BT_ALERT_LEVEL_NONE ( = 0 ) to it, to initialize bonding:


- (void) writeLinkLossAlertLevelToTag:(UInt8) linkLossAlertLevel
{
  NSData* data = [NSData dataWithBytes:&linkLossAlertLevel length:1];
  [selectedPeripheral writeValue:data forCharacteristic:linkLossAlertLevelCharacteristic type:CBCharacteristicWriteWithResponse];
}
- (bool) writeLinkLossAlert:(UInt8)level
{
  if(linkLossAlertLevelCharacteristic != nil) {
    NSLog(@"INFO: Writes link loss alert %d to peripheral...", level);
    [self writeLinkLossAlertLevelToTag:level];
    return YES;
  }
  NSLog(@"ERROR: Couldn´t write to alert level on link loss service.");
  return NO;
}


8. The "Pairing" dialog appears and is confirmed to pair with. But instead of pairing the write fails and there after i also get a disconnect with the timeout error.


It works all fine until iOS 9 and i don't use any deprecated API's


I logged the delegate callbacks from CBCentralManager and CBPeripheral:

2015-10-30 11:38:07.881 BLEControl[307:32547] INFO: Bluetooth is enabled

2015-10-30 11:38:14.423 BLEControl[307:32547] INFO: Start to scan for peripherals

2015-10-30 11:38:14.456 BLEControl[307:32547] INFO: Did discover peripheral <Torantrieb> with identifier <<__NSConcreteUUID 0x15d70340> 0545B850-B6BE-1BB9-10E7-80E3559AC9FB>

2015-10-30 11:38:18.129 BLEControl[307:32547] INFO: Stopped to scan for peripherals

2015-10-30 11:38:18.164 BLEControl[307:32547] INFO: Did connect to peripheral <Torantrieb> with identifier <<__NSConcreteUUID 0x15d70340> 0545B850-B6BE-1BB9-10E7-80E3559AC9FB>

2015-10-30 11:38:18.362 BLEControl[307:32547] INFO: Did discover 3 services on Torantrieb

2015-10-30 11:38:18.363 BLEControl[307:32547] INFO: Did discover service 1804 on Torantrieb

2015-10-30 11:38:18.364 BLEControl[307:32547] INFO: Did discover service 1802 on Torantrieb

2015-10-30 11:38:18.364 BLEControl[307:32547] INFO: Did discover service 1803 on Torantrieb

2015-10-30 11:38:18.366 BLEControl[307:32547] INFO: Did discover 0 characteristics for service <CBService: 0x15d85a00, isPrimary = YES, UUID = 1804> on peripheral <CBPeripheral: 0x15d85de0, identifier = 0545B850-B6BE-1BB9-10E7-80E3559AC9FB, name = Torantrieb, state = connected>

2015-10-30 11:38:18.367 BLEControl[307:32547] INFO: Did discover 1 characteristics for service <CBService: 0x15d8d5e0, isPrimary = YES, UUID = 1802> on peripheral <CBPeripheral: 0x15d85de0, identifier = 0545B850-B6BE-1BB9-10E7-80E3559AC9FB, name = Torantrieb, state = connected>

2015-10-30 11:38:18.367 BLEControl[307:32547] INFO: Did discover characteristic 2a06 for service <CBService: 0x15d8d5e0, isPrimary = YES, UUID = 1802> on peripheral <CBPeripheral: 0x15d85de0, identifier = 0545B850-B6BE-1BB9-10E7-80E3559AC9FB, name = Torantrieb, state = connected>

2015-10-30 11:38:18.367 BLEControl[307:32547] INFO: Did discover 1 characteristics for service <CBService: 0x15d8d620, isPrimary = YES, UUID = 1803> on peripheral <CBPeripheral: 0x15d85de0, identifier = 0545B850-B6BE-1BB9-10E7-80E3559AC9FB, name = Torantrieb, state = connected>

2015-10-30 11:38:18.369 BLEControl[307:32547] INFO: Did discover characteristic 2a06 for service <CBService: 0x15d8d620, isPrimary = YES, UUID = 1803> on peripheral <CBPeripheral: 0x15d85de0, identifier = 0545B850-B6BE-1BB9-10E7-80E3559AC9FB, name = Torantrieb, state = connected>

2015-10-30 11:38:18.370 BLEControl[307:32547] INFO: Writes link loss alert 0 to peripheral...

2015-10-30 11:38:22.354 BLEControl[307:32547] ERROR: Failed to write value for characteristic <CBCharacteristic: 0x15d8d890, UUID = 2A06, properties = 0xA, value = (null), notifying = NO>, reason: Error Domain=CBATTErrorDomain Code=15 "Encryption is insufficient." UserInfo={NSLocalizedDescription=Encryption is insufficient.}

2015-10-30 11:38:23.145 BLEControl[307:32547] ERROR: Did disconnect peripheral <Torantrieb> with identifier <<__NSConcreteUUID 0x15d70340> 0545B850-B6BE-1BB9-10E7-80E3559AC9FB>: Error Domain=CBErrorDomain Code=6 "The connection has timed out unexpectedly." UserInfo={NSLocalizedDescription=The connection has timed out unexpectedly.} {

NSLocalizedDescription = "The connection has timed out unexpectedly.";

}


Here is the full code of my Test-View Controller


ViewController.h

#import <UIKit/UIKit.h>
#import <CoreBluetooth/CoreBluetooth.h>
@interface CBUUID (StringExtraction)
- (NSString *)representativeString;
@end

@interface ViewController : UIViewController <UITableViewDelegate,UITableViewDataSource,CBCentralManagerDelegate,CBPeripheralDelegate>
@end

ViewController.m


#import "ViewController.h"

#define findMeServiceUUID            [CBUUID UUIDWithString:@"1802"]
#define genericAccessServiceUUID      [CBUUID UUIDWithString:@"1800"]
#define linkLossServiceUUID          [CBUUID UUIDWithString:@"1803"]
#define deviceNameCharacteristicUUID  [CBUUID UUIDWithString:@"2A00"]
#define alertLevelCharacteristicUUID  [CBUUID UUIDWithString:@"2A06"]
#define BT_ALERT_LEVEL_NONE 0
#define BT_LEVEL_MILD 1
#define BT_ALERT_LEVEL_HIGH 2
#define BT_ALERT_LEVEL_RESERVED(LVL) LVL

@implementation CBUUID (StringExtraction)
- (NSString *)representativeString;
{
  NSData *data = [self data];

  NSUInteger bytesToConvert = [data length];
  const unsigned char *uuidBytes = [data bytes];
  NSMutableString *outputString = [NSMutableString stringWithCapacity:16];

  for (NSUInteger currentByteIndex = 0; currentByteIndex < bytesToConvert; currentByteIndex++)
  {
    switch (currentByteIndex)
    {
      case 3:
      case 5:
      case 7:
      case 9:[outputString appendFormat:@"%02x-", uuidBytes[currentByteIndex]]; break;
      default:[outputString appendFormat:@"%02x", uuidBytes[currentByteIndex]];
    }

  }
  return outputString;
}
@end

@interface ViewController ()
@end

@implementation ViewController {
  NSMutableArray* peripherals;
  BOOL isScanning;
  BOOL isPairing;
  BOOL isBonded;
  BOOL isConnected;
  BOOL hasFailed;

  CBCentralManager* centralManager;

  CBPeripheral* selectedPeripheral;
  CBService *immediateAlertService;
  CBCharacteristic *immediateAlertAlertLevelCharacteristic;

  CBService *linkLossService;
  CBCharacteristic *linkLossAlertLevelCharacteristic;

  IBOutlet UILabel* labelPeripheral;
  IBOutlet UIButton* buttonScan;
  IBOutlet UITableView* tablePeripherals;
}
-(id)initWithCoder:(NSCoder *)aDecoder {
  self = [super initWithCoder:aDecoder];
  if(!self)
    return self;

  peripherals = [[NSMutableArray alloc] init];
  centralManager = [[CBCentralManager alloc] initWithDelegate:self queue:nil];
  return self;
}
- (void)viewDidLoad {
  [super viewDidLoad];
  [self updateLabel];
}
- (void)didReceiveMemoryWarning {
  [super didReceiveMemoryWarning];
}
#pragma mark - BLE
-(void)startScan {
  if(isScanning)
    return;

  [centralManager stopScan];
  [peripherals removeAllObjects];
  [self reloadTable];

  NSDictionary* scanOptions = [NSDictionary dictionaryWithObject:[NSNumber numberWithBool:NO]
                                                          forKey:CBCentralManagerScanOptionAllowDuplicatesKey];
  NSArray* serviceArray = [NSArray arrayWithObjects:findMeServiceUUID,linkLossServiceUUID, nil];

  [centralManager scanForPeripheralsWithServices:serviceArray options:scanOptions];

  NSLog(@"INFO: Start to scan for peripherals");
  isScanning = YES;
}
-(void)stopScan {

  /

  if(!isScanning)
    return;

  [centralManager stopScan];
  NSLog(@"INFO: Stopped to scan for peripherals");

  isScanning = NO;
}
-(void)pairPeripheral {

  if(!selectedPeripheral || isPairing)
    return;

  isPairing = YES;
  selectedPeripheral.delegate = self;

  [self updateLabel];

  [self connectPeripheral];
}
-(void)connectPeripheral {
  if(!selectedPeripheral || isConnected)
    return;

  NSDictionary* connectOptions = [NSDictionary dictionaryWithObject:[NSNumber numberWithBool:YES]
                                                            forKey:CBConnectPeripheralOptionNotifyOnDisconnectionKey];
  [centralManager connectPeripheral:selectedPeripheral options:connectOptions];
}
-(void)disconnectPeripheral {
  if(!selectedPeripheral || !isConnected)
    return;

  [centralManager cancelPeripheralConnection:selectedPeripheral];
}
-(void)alertPeripheral {
  if(!selectedPeripheral || !isBonded)
    return;

  [self writeImmediateAlert:BT_ALERT_LEVEL_RESERVED(3)];
}
- (void) writeLinkLossAlertLevelToTag:(UInt8) linkLossAlertLevel
{
  NSData* data = [NSData dataWithBytes:&linkLossAlertLevel length:1];
  [selectedPeripheral writeValue:data forCharacteristic:linkLossAlertLevelCharacteristic type:CBCharacteristicWriteWithResponse];
}
- (bool) writeLinkLossAlert:(UInt8)level
{
  if(linkLossAlertLevelCharacteristic != nil) {
    NSLog(@"INFO: Writes link loss alert %d to peripheral...", level);
    [self writeLinkLossAlertLevelToTag:level];
    return YES;
  }
  NSLog(@"ERROR: Couldn´t write to alert level on link loss service.");
  return NO;
}
- (void) writeImmediateAlertLevelToTag:(UInt8) immediateAlertLevel
{
  NSData* data = [NSData dataWithBytes:&immediateAlertLevel length:1];
  [selectedPeripheral writeValue:data forCharacteristic:immediateAlertAlertLevelCharacteristic type:CBCharacteristicWriteWithoutResponse];
}
- (bool) writeImmediateAlert:(UInt8)level
{
  if(immediateAlertAlertLevelCharacteristic != nil) {
    NSLog(@"INFO: Writes immediate alert %d to tag...", level);
    [self writeImmediateAlertLevelToTag:level];
    return YES;
  }
  NSLog(@"INFO: Couldn´t write to alert level on immediate alert service.");
  return NO;
}
#pragma mark - CentralManager delegate
- (void) centralManagerDidUpdateState:(CBCentralManager *)central
{
  if ([central state] == CBCentralManagerStatePoweredOn)
    NSLog(@"INFO: Bluetooth is enabled");
  else
  {
    NSLog(@"WARNING: Bluetooth is not enabled");
    [labelPeripheral setText:@"Bluetooth is not enabled!"];
  }
}
- (void) centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI
{
  NSLog(@"INFO: Did discover peripheral <%@> with identifier <%@>", peripheral.name, peripheral.identifier);
  [peripherals addObject:peripheral];
  [self reloadTable];
}
- (void) centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral
{
  NSLog(@"INFO: Did connect to peripheral <%@> with identifier <%@>", peripheral.name, peripheral.identifier);

  isConnected = YES;
  [self updateLabel];

  [peripheral discoverServices:nil];
}
- (void) centralManager:(CBCentralManager *)central didDisconnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error
{
  isConnected = NO;
  if(error) {
    NSLog(@"ERROR: Did disconnect peripheral <%@>  with identifier <%@>: %@ %@", peripheral.name, peripheral.identifier, error, [error userInfo]);

    if(isPairing) {
      hasFailed = YES;
      isPairing = NO;
      [self updateLabel];
    }
    return;
  }
  [self updateLabel];
  NSLog(@"INFO: Did disconnect peripheral <%@> with identifier <%@>", peripheral.name, peripheral.identifier);
}
- (void)centralManager:(CBCentralManager *)central didFailToConnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error {
  isPairing = NO;
  [self updateLabel];

  if(error) {
    NSLog(@"ERROR: Did failed to connect to peripheral <%@>  with identifier <%@>: %@ %@", peripheral.name, peripheral.identifier, error, [error userInfo]);
    return;
  }
  NSLog(@"WARNING: Did failed to connect to peripheral <%@>  with identifier <%@>", peripheral.name, peripheral.identifier);
}
#pragma mark - Peripheral delegate
- (void) peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error
{
  NSLog(@"INFO: Did discover %d services on %@", (int)[peripheral services].count, [peripheral name]);
  for(CBService *s in [peripheral services]) {
    if([[s UUID] isEqual:findMeServiceUUID])
      immediateAlertService = s;

    if([[s UUID] isEqual:linkLossServiceUUID])
      linkLossService = s;

    NSLog(@"INFO: Did discover service %@ on %@", [s.UUID representativeString], [peripheral name]);
    [peripheral discoverCharacteristics:[NSArray arrayWithObject:alertLevelCharacteristicUUID] forService:s];
  }
}
- (void) peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error
{
  NSLog(@"INFO: Did discover %d characteristics for service %@ on peripheral %@", (int)service.characteristics.count, service, peripheral);
  for(CBCharacteristic *c in [service characteristics])
  {
    NSLog(@"INFO: Did discover characteristic %@ for service %@ on peripheral %@", [c.UUID representativeString], service, peripheral);
    if([service isEqual:immediateAlertService] &&
      [[c UUID] isEqual:alertLevelCharacteristicUUID])
      immediateAlertAlertLevelCharacteristic = c;

    else if([service isEqual:linkLossService] &&
            [[c UUID] isEqual:alertLevelCharacteristicUUID]) {
   
      if(isBonded)
        return;
   
      linkLossAlertLevelCharacteristic = c;
      if(linkLossAlertLevelCharacteristic)
        [self writeLinkLossAlert:BT_ALERT_LEVEL_NONE];
   
    }
  }
}
- (void) peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error
{
  NSLog(@"INFO: Did update value for characteristic %@, new value: %@, error: %@", characteristic, [characteristic value], error);
}
- (void) peripheral:(CBPeripheral *)peripheral didWriteValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error
{
  if (error)
  {
    NSLog(@"ERROR: Failed to write value for characteristic %@, reason: %@", characteristic, error);
  }
  else
  {
    NSLog(@"INFO: Did write value for characterstic %@, new value: %@", characteristic, [characteristic value]);

    isPairing = NO;
    isBonded = YES;

    [self updateLabel];
  }
}
#pragma mark - UI
-(IBAction)onScanButton:(id)sender {

  if(!isScanning) {
    [self startScan];
    [buttonScan setTitle:@"Stop" forState:UIControlStateNormal];
  }
  else {
    [self stopScan];
    [buttonScan setTitle:@"Start" forState:UIControlStateNormal];
  }
  [self updateLabel];
}
-(IBAction)onConnectButton:(id)sender {
  [self connectPeripheral];
}
-(IBAction)onDisconnectButton:(id)sender {
  [self disconnectPeripheral];
}
-(IBAction)onAlertButton:(id)sender {
  [self alertPeripheral];
}
-(void) updateLabel {
  if(!selectedPeripheral) {
    if(!isScanning)
      [labelPeripheral setText:@"Press start to scan"];
    else
      [labelPeripheral setText:@"Scanning..."];
    return;
  }

  if(hasFailed) {
    [labelPeripheral setText:[NSString stringWithFormat:@"%@ pairing failed", selectedPeripheral.name]];
    return;
  }

  if(isBonded) {
    [labelPeripheral setText:[NSString stringWithFormat:@"%@ bonded", selectedPeripheral.name]];
    return;
  }

  if(isConnected) {
    [labelPeripheral setText:[NSString stringWithFormat:@"%@ connected", selectedPeripheral.name]];
    return;
  }
  if(isPairing) {
    [labelPeripheral setText:[NSString stringWithFormat:@"%@ pairing...", selectedPeripheral.name]];
    return;
  }
}
#pragma Mark - Validating
-(CBPeripheral*)getPeripheral:(NSInteger)arrayIndex {
  CBPeripheral* peripheral = NULL;

  if(!peripherals)
    NSLog(@"FATAL: Peripherals array is NULL");
  else {
    if(peripherals.count < arrayIndex)
      NSLog(@"FATAL: Peripherals array length is too short.");


    peripheral = [peripherals objectAtIndex:arrayIndex];
    if(!peripheral)
      NSLog(@"FATAL: Peripheral is NULL.");
  }

  return peripheral;
}
# pragma mark - TableView thread synchronization
-(void)reloadTable {

  [tablePeripherals performSelectorOnMainThread:@selector(reloadData)
                                    withObject:nil
                                  waitUntilDone:YES];
}
#pragma mark - TableView dataSource and delegate
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
  return 64;
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
  return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
  if(!peripherals)
    return 0;

  return [peripherals count];
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {


  selectedPeripheral = [self getPeripheral:indexPath.item];
  if(!selectedPeripheral)
    return;

  if(isScanning)
    [self onScanButton:buttonScan];
  [self pairPeripheral];
}
-(UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
  UITableViewCell* cell = [tableView dequeueReusableCellWithIdentifier:@"SettingsCell"];
  if(!cell) {
    cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"SettingsCell"];
    cell.selectionStyle = UITableViewCellSelectionStyleBlue;
  }

  CBPeripheral* peripheral = [self getPeripheral:indexPath.item];
  if(!peripheral) {
    [cell.textLabel setText:@"<Unexpected error>"];
    return cell;
  }

  [cell.textLabel setText:peripheral.name];
  return cell;
}
@end

Please refer to my answer about this issue on the other thread: https://forums.developer.apple.com/thread/20585