Что вызывает CBCentralManagerStateUnknown в iOS?

Почему я получаю CBCentralManagerStateUnknown на iPad 2 при использовании этого простого кода?

- (BOOL)viewDidLoad {

    bluetoothManager = [[CBCentralManager alloc] initWithDelegate:self queue:nil];

    if ([manager state] == CBCentralManagerStatePoweredOff) NSLog(@"CBCentralManagerStatePoweredOff");
    if ([manager state] == CBCentralManagerStatePoweredOn) NSLog(@"CBCentralManagerStatePoweredOn");
    if ([manager state] == CBCentralManagerStateResetting) NSLog(@"CBCentralManagerStateResetting");
    if ([manager state] == CBCentralManagerStateUnauthorized) NSLog(@"CBCentralManagerStateUnauthorized");
    if ([manager state] == CBCentralManagerStateUnknown) NSLog(@"CBCentralManagerStateUnknown");
    if ([manager state] == CBCentralManagerStateUnsupported) NSLog(@"CBCentralManagerStateUnsupported");

}

Я не могу понять, что означает CBCentralManagerStateUnknown. Что я делаю? Apple docs просто скажут:

Состояние неизвестно, обновление не ожидается.

Я получаю этот ответ с подключенным Bluetooth-устройством, а также когда Bluetooth выключен. Если я попытаюсь запустить что-то вроде [manager retrieveConnectedPeripherals], я также получаю это сообщение в консоли:

CoreBluetooth[WARNING] <CBConcreteCentralManager: ...> is not powered on

Ответ 1

Я знаю, почему делегат никогда не вызывается. Поскольку объект удаляется из памяти. Просто сделайте сильное свойство

@property (strong, nonatomic) DiscoverBluetoothDevices *btDevices;

И в init

@implementation DiscoverBluetoothDevices
- (id) init
{
    self = [super init];
    if(self) {
        centralManager = [[CBCentralManager alloc] initWithDelegate:self queue:dispatch_get_main_queue()];
        [centralManager scanForPeripheralsWithServices:nil options:@{CBCentralManagerScanOptionAllowDuplicatesKey: @YES}];

    }
    return self;
}

И теперь делегат называется правильно.

Ответ 2

CBCentralManagerStateUnknown просто означает, что iOS запустил процесс BLE, но не завершил инициализацию. Дайте ему момент, и состояние изменится.

В общем, вы "дадите ему мгновение", обнаружив состояние изменения в обработчике делегата CBCentralManagerDelegate, вместо того, чтобы смотреть на него сразу после вызова инициализации. Вы реализуете

- (void) centralManagerDidUpdateState: (CBCentralManager *) central;

Есть несколько хороших примеров, которые показывают это, например, Apple монитор сердечного ритма.

Ответ 3

Если центральное состояние переходит на CBCentralManagerStateUnsupported (в то время как Bluetooth Low Energy поддерживается устройством), это скорее всего означает, что приложение сделало что-то плохое с CoreBluetooth.

Проверьте журнал iOS Bluetooth Diagnostic Logging.

Например, если вы это сделаете...

_cm1 = [[CBCentralManager alloc] initWithDelegate:self queue:nil options:@{ CBCentralManagerOptionRestoreIdentifierKey: @"not_unique" }]; _cm2 = [[CBCentralManager alloc] initWithDelegate:self queue:nil options:@{ CBCentralManagerOptionRestoreIdentifierKey: @"not_unique" }];

... второе центральное состояние перейдет к CBCentralManagerStateUnsupported.

Ответ 4

Фактический ответ (старый вопрос, который я знаю); начните сканирование периферийных устройств, это запустит BT LE, и ваши делегаты получат обратный вызов. Мои делегаты и информация о штате не изменились, пока я не сделал это.

а. Настройте свой cbcentralmanager, как показано ниже. б. У вас есть -central * делегаты в вашем коде и в вашем файле .h с. NSLog или обновить ярлык на экране с новым статусом. И... Успех.

cManager = [[CBCentralManager alloc] initWithDelegate:self queue:nil];

[cManager scanForPeripheralsWithServices:nil options:@{CBCentralManagerScanOptionAllowDuplicatesKey: @YES}];

Ответ 5

Вам нужно сохранить экземпляр CBCentralManager (поместить его в ivar или private property) и дождаться, когда будет вызван делегат изменения состояния. (Состояние всегда "неизвестно", если вы проверяете его сразу после создания экземпляра менеджера. В методе делегата мгновенно появится реальное состояние.)

Ответ 6

В моем случае я использовал приложение AppDelegate в качестве делегата для

CBCentralManagerDelegate

и косвенно для

 AVCaptureMetadataOutputObjectsDelegate.

за один раз.

1) Позаботьтесь о потоках. Используйте

dispatch_get_main_queue() 

или

[NSThread mainThread]

для работы с BLE.

2) Позаботьтесь об использовании этих 2 делегатов на 1 объекте. Поскольку аппаратное обеспечение НЕ thead и контекст сохранить