Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to resolve the "NSInternalInconsistencyException" error in Objective-C?

I am new to Objective-C and IOS development. I am try to developing the App with BLE.

I follow the DarkBlue and add the following code at viewDidLoad in the ViewController.m

- (void)viewDidLoad
{
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
    self.defaultBTServer = [BTServer defaultBTServer];
    self.defaultBTServer.delegate = (id)self;
    [self.defaultBTServer startScan];

}

And the BTServer is like the following code:

//
//  BTServer.m
//  DarkBlue
//
//  Created by chenee on 14-3-26.
//  Copyright (c) 2014年 chenee. All rights reserved.
//

#import "BTServer.h"

@interface BTServer()


@end


@implementation BTServer{
    BOOL inited;
    CBCentralManager *myCenter;
    //state
    NSInteger scanState;
    NSInteger connectState;
    NSInteger serviceState;
    NSInteger characteristicState;
    NSInteger readState;


    eventBlock connectBlock;

//    CBPeripheral *m_Peripheral;

}

static BTServer* _defaultBTServer = nil;
-(NSInteger)getScanState
{
    return scanState;
}
-(NSInteger)getConnectState
{
    return connectState;
}
-(NSInteger)getServiceState
{
    return serviceState;
}
-(NSInteger)getCharacteristicState
{
    return characteristicState;
}
-(NSInteger)getReadState
{
    return readState;
}


+(BTServer*)defaultBTServer
{
    if (nil == _defaultBTServer) {
        _defaultBTServer = [[BTServer alloc]init];

        [_defaultBTServer initBLE];
    }

    return _defaultBTServer;
}

-(void)initBLE
{
    if (inited) {
        return;
    }
    inited = TRUE;
    self.delegate = nil;
    self.discoveredPeripherals = [NSMutableArray array];
//    self.services = [NSMutableArray array];
    self.selectPeripheral = nil;
    connectState = KNOT;
    connectBlock = nil;

    NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithBool:YES], CBCentralManagerOptionShowPowerAlertKey, @"zStrapRestoreIdentifier",CBCentralManagerOptionRestoreIdentifierKey,nil];

    myCenter = [[CBCentralManager alloc]
                           initWithDelegate:self
                           queue:dispatch_queue_create("com.myBLEQueue", NULL)
                           options:options]; // TODO: options

    NSLog(@"init bt server ........");

}
-(void)finishBLE
{
    //??
}

#pragma mark -- APIs
-(void)startScan
{
    [self startScan:10];
}
-(void)startScan:(NSInteger)forLastTime
{
    [self.discoveredPeripherals removeAllObjects];
    scanState = KING;

    //0:retrive
#if 1
    //method 1:
    NSArray *atmp = [NSArray arrayWithObjects:[CBUUID UUIDWithString:UUIDPrimaryService],[CBUUID UUIDWithString:UUIDPrimaryService2], nil];
    NSArray *retrivedArray = [myCenter retrieveConnectedPeripheralsWithServices:atmp];
    NSLog(@"retrivedArray:\n%@",retrivedArray);

    for (CBPeripheral* peripheral in retrivedArray) {
        [self addPeripheral:peripheral advertisementData:nil  RSSI:nil];
    }

    //method 2:
//    [myCenter retrieveConnectedPeripherals];//XXX: deprecated\ˈdɛprɪˌket\ but still work

#endif
    //1: scan
//    NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithBool:YES], CBCentralManagerScanOptionAllowDuplicatesKey, nil];
//    [myCenter scanForPeripheralsWithServices:[NSArray arrayWithObject:[CBUUID UUIDWithString:@"0xFFA0"]]  options:options];
    [myCenter scanForPeripheralsWithServices:nil options:nil];


    if (forLastTime > 0) {
//        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(forLastTime * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
//            [self stopScan];
//        });
//        [NSTimer scheduledTimerWithTimeInterval:forLastTime target:self selector:@selector(stopScan) userInfo:nil repeats:NO];
        [NSObject cancelPreviousPerformRequestsWithTarget:self
                                                 selector:@selector(stopScan)
                                                   object:nil];
        [self performSelector:@selector(stopScan)
                   withObject:nil
                   afterDelay:forLastTime];
    }
}
-(void)stopScan:(BOOL)withOutEvent
{

    if (scanState != KING) {
        return;
    }

    NSLog(@"stop scan ...");

    scanState = KSUCCESS;
    [myCenter stopScan];

    if(withOutEvent)
        return;

    if (self.delegate) {
        if([(id)self.delegate respondsToSelector:@selector(didStopScan)]){
            [self.delegate didStopScan];
        }
    }
}
-(void)stopScan
{
    [self stopScan:FALSE];
}
-(void)cancelConnect
{
    if (myCenter && self.selectPeripheral) {
        if(self.selectPeripheral.state == CBPeripheralStateConnecting){
            NSLog(@"timeout cancel connect to peripheral:%@",self.selectPeripheral.name);

            [myCenter cancelPeripheralConnection:self.selectPeripheral];
            connectState = KNOT;
        }
    }
}
-(void)connect:(PeriperalInfo *)peripheralInfo
{
    NSLog(@"connecting to peripheral:%@",peripheralInfo.peripheral.name);

    [myCenter connectPeripheral:peripheralInfo.peripheral options:@{CBConnectPeripheralOptionNotifyOnConnectionKey: @YES, CBConnectPeripheralOptionNotifyOnDisconnectionKey: @YES, CBConnectPeripheralOptionNotifyOnNotificationKey: @YES}];

    self.selectPeripheral = peripheralInfo.peripheral;
    connectState = KING;

//    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(AUTO_CANCEL_CONNECT_TIMEOUT * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
//        [self cancelConnect];
//
//    });
//    [NSTimer scheduledTimerWithTimeInterval:AUTO_CANCEL_CONNECT_TIMEOUT target:self selector:@selector(cancelConnect) userInfo:nil repeats:NO];
    [NSObject cancelPreviousPerformRequestsWithTarget:self
                                             selector:@selector(cancelConnect)
                                               object:nil];
    [self performSelector:@selector(stopScan)
               withObject:nil
               afterDelay:AUTO_CANCEL_CONNECT_TIMEOUT];
}

-(void)connect:(PeriperalInfo *)peripheralInfo withFinishCB:(eventBlock)callback
{
    [self connect:peripheralInfo];
    connectBlock = callback;
}
-(void)disConnect
{
    if(myCenter && self.selectPeripheral){
        [myCenter cancelPeripheralConnection:self.selectPeripheral];
    }
}
-(void)discoverService:(CBService*)service
{
    if(self.selectPeripheral){
        characteristicState = KING;
        self.discoveredSevice = service;
        [self.selectPeripheral discoverCharacteristics:nil forService:service];
    }

}
-(void)readValue:(CBCharacteristic*)characteristic
{
    if (readState == KING) {
        NSLog(@"BTServer: should wait read over");
        return;
    }
    if (characteristic != nil) {
        self.selectCharacteristic = characteristic;
    }
    readState = KING;
    [self.selectPeripheral readValueForCharacteristic:self.selectCharacteristic];
}

#pragma mark CBCentralManagerDelegate
-(void)addPeripheralInfo:(PeriperalInfo *)peripheralInfo
{
    for(int i=0;i<self.discoveredPeripherals.count;i++){
        PeriperalInfo *pi = self.discoveredPeripherals[i];

        if([peripheralInfo.uuid isEqualToString:pi.uuid]){
            [self.discoveredPeripherals replaceObjectAtIndex:i withObject:peripheralInfo];
            return;
        }
    }

    [self.discoveredPeripherals addObject:peripheralInfo];

    if (self.delegate) {
        if([(id)self.delegate respondsToSelector:@selector(didFoundPeripheral)]){
            [self.delegate didFoundPeripheral];
        }
    }
}
-(void)addPeripheral:(CBPeripheral*)peripheral advertisementData:(NSDictionary*)advertisementData RSSI:(NSNumber*)RSSI
{
    PeriperalInfo *pi = [[PeriperalInfo alloc]init];

    pi.peripheral = peripheral;
    pi.uuid = [peripheral.identifier UUIDString];
    pi.name = peripheral.name;
    switch (peripheral.state) {
        case CBPeripheralStateDisconnected:
            pi.state = @"disConnected";
            break;
        case CBPeripheralStateConnecting:
            pi.state = @"connecting";
            break;
        case CBPeripheralStateConnected:
            pi.state = @"connected";
            break;
        default:
            break;
    }
    //    pi.channel = advertisementData objectForKey:
    if (advertisementData) {
        pi.localName = [advertisementData objectForKey:CBAdvertisementDataLocalNameKey];
        NSArray *array = [advertisementData objectForKey:CBAdvertisementDataServiceUUIDsKey];
        pi.serviceUUIDS = [array componentsJoinedByString:@"; "];
    }


    if (RSSI) {
        pi.RSSI = RSSI;
    }

    [self addPeripheralInfo:pi];
}

- (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI
{
//    NSLog(@"discover peripheral: %@; advertisementData: %@; RSSI: %@", peripheral, advertisementData, RSSI);
    NSLog(@"discover peripheral: %@; RSSI: %@", peripheral.name, RSSI);

    [self addPeripheral:peripheral advertisementData:advertisementData RSSI:RSSI];


}
- (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral
{
    NSLog(@"didconnect to peripheral: %@",peripheral.name);

    connectState = KSUCCESS;
    if (connectBlock) {
        connectBlock(peripheral,true,nil);
        connectBlock = nil;
    }


    self.selectPeripheral = peripheral;
    self.selectPeripheral.delegate = self;
    serviceState = KING;
    [self.selectPeripheral discoverServices:nil];
}

- (void)centralManager:(CBCentralManager *)central didDisconnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error
{
    NSLog(@"didDisConnected peripheral: %@",peripheral.name);

    connectState = KFAILED;
    if (connectBlock) {
        connectBlock(peripheral,false,nil);
        connectBlock = nil;
    }

    if (self.delegate) {
        if([(id)self.delegate respondsToSelector:@selector(didDisconnect)]){
            [self.delegate didDisconnect];
        }
    }
}

- (void)centralManager:(CBCentralManager *)central didFailToConnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error
{
    NSLog(@"DidFailToConnectPeripheral .....");
}



- (void)centralManager:(CBCentralManager *)central didRetrieveConnectedPeripherals:(NSArray *)peripherals
{
    NSLog(@"retrive connected peripheral %@",peripherals);
}

- (void)centralManager:(CBCentralManager *)central didRetrievePeripherals:(NSArray *)peripherals
{
    NSLog(@"retrive %@",peripherals);

}

- (void)centralManagerDidUpdateState:(CBCentralManager *)central
{
    // Determine the state of the peripheral
    if ([central state] == CBCentralManagerStatePoweredOff) {
        NSLog(@"CoreBluetooth BLE hardware is powered off");
    }
    else if ([central state] == CBCentralManagerStatePoweredOn) {
        NSLog(@"CoreBluetooth BLE hardware is powered on and ready");
    }
    else if ([central state] == CBCentralManagerStateUnauthorized) {
        NSLog(@"CoreBluetooth BLE state is unauthorized");
    }
    else if ([central state] == CBCentralManagerStateUnknown) {
        NSLog(@"CoreBluetooth BLE state is unknown");
    }
    else if ([central state] == CBCentralManagerStateUnsupported) {
        NSLog(@"CoreBluetooth BLE hardware is unsupported on this platform");
    }

}

- (void)centralManager:(CBCentralManager *)central willRestoreState:(NSDictionary *)dict
{
    NSLog(@"will restore ....");
}


#pragma mark CBPeripheralDelegate

- (void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error
{
    if (nil == error) {
        serviceState = KSUCCESS;
//        NSLog(@"found services:\n%@",peripheral.services);
    }else{
        serviceState = KFAILED;
        NSLog(@"discover service failed:%@",error);
    }
}

- (void)peripheral:(CBPeripheral *)peripheral didDiscoverIncludedServicesForService:(CBService *)service error:(NSError *)error
{
}

- (void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error
{
    if (nil == error) {
        characteristicState = KSUCCESS;
        self.discoveredSevice = service;
    }else{
        characteristicState = KFAILED;
        self.discoveredSevice = nil;
        NSLog(@"discover characteristic failed:%@",error);
    }

}

- (void)peripheral:(CBPeripheral *)peripheral didDiscoverDescriptorsForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error
{

}


- (void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error
{
    if (error){
        readState = KFAILED;
        NSLog(@"Error updating value for characteristic %@ error: %@", characteristic.UUID, [error localizedDescription]);
        return;
    }

    readState = KSUCCESS;
    self.selectCharacteristic = characteristic;
    if (self.delegate && [(id)self.delegate respondsToSelector:@selector(didReadvalue)])
        [self.delegate didReadvalue];
}

- (void)peripheral:(CBPeripheral *)peripheral didUpdateValueForDescriptor:(CBDescriptor *)descriptor error:(NSError *)error
{
}

- (void)peripheral:(CBPeripheral *)peripheral didWriteValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error
{

}

- (void)peripheral:(CBPeripheral *)peripheral didWriteValueForDescriptor:(CBDescriptor *)descriptor error:(NSError *)error
{
}

- (void)peripheral:(CBPeripheral *)peripheral didUpdateNotificationStateForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error
{
}

- (void)peripheralDidUpdateRSSI:(CBPeripheral *)peripheral error:(NSError *)error
{
}

- (void)peripheralDidUpdateName:(CBPeripheral *)peripheral
{
}

- (void)peripheral:(CBPeripheral *)peripheral didModifyServices:(NSArray *)invalidatedServices
{
}



@end

But I got the error like the following:

2014-04-10 20:28:24.375 BLE_Running[939:60b] *** Assertion failure in -[CBCentralManager initWithDelegate:queue:options:], /SourceCache/CoreBluetooth/CoreBluetooth-109/CBCentralManager.m:168
2014-04-10 20:28:24.378 BLE_Running[939:60b] *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'State restoration of CBCentralManager is only allowed for applications that have specified the "bluetooth-central" background mode'
*** First throw call stack:
(0x2fc51f03 0x3a3e6ce7 0x2fc51dd5 0x305fee2f 0x2f971d23 0x8da9d 0x8d7d1 0x89431 0x32485a53 0x32485811 0x3248c489 0x32489dd9 0x324f3a51 0x324f06e5 0x324eacc9 0x32486c97 0x32485df9 0x324ea405 0x34af3b55 0x34af373f 0x2fc1c83f 0x2fc1c7db 0x2fc1afa7 0x2fb857a9 0x2fb8558b 0x324e962b 0x324e4891 0x906b1 0x3a8e4ab7)
libc++abi.dylib: terminating with uncaught exception of type NSException
(lldb)

I have reference the link similar problem , and add the Required background modes like the following picture enter image description here

But it seems doesn't work...

Does there has any idea for this error ?

Thanks in advance.

like image 662
Martin Avatar asked Dec 14 '22 23:12

Martin


1 Answers

I following the link : Core Bluetooth Background Execution Modes

In Info.plist

Right click and select the Show Raw Keys/Values

At the UIBackgroundModes , add the item and it can see the bluetooth-central.

like image 172
Martin Avatar answered Jan 04 '23 06:01

Martin