2014-12-05 53 views
1

我有一個視圖控制器,當您按下按鈕時啓動藍牙掃描。centralManagerDidUpdateState拋出無法識別的選擇器發送到實例錯誤

這裏是.h文件:

#import <UIKit/UIKit.h> 
@import CoreBluetooth; 

@interface ViewControllerIntroPage2 : UIViewController{ 
    IBOutlet UIButton *scanForFetchTagsButton; 
} 

@property (nonatomic, retain) UIButton *scanForFetchTagsButton; 
@property (nonatomic, retain) CBCentralManager *mCentralManager; 

-(IBAction)scanButtonPressed:(id)sender; 

@end 

這裏是.m文件:

#import "ViewControllerIntroPage2.h" 
#import "BlueToothLEManager.h" 

@interface ViewControllerIntroPage2() 

@end 

@implementation ViewControllerIntroPage2 

@synthesize scanForFetchTagsButton; 

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil 
{ 
    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]; 
    if (self) { 
     // Custom initialization 
    } 
    return self; 
} 

- (void)viewDidLoad 
{ 
    [super viewDidLoad]; 
    // Do any additional setup after loading the view. 
} 

- (void)didReceiveMemoryWarning 
{ 
    [super didReceiveMemoryWarning]; 
    // Dispose of any resources that can be recreated. 
} 

-(IBAction)scanButtonPressed:(id)sender { 
    NSLog(@"Scan Button Clicked"); 

    self.mCentralManager = [[BlueToothLEManager alloc]initializeCBCentralManager]; 

    NSLog(@"Scan Done"); 
} 
/* 
#pragma mark - Navigation 

// In a storyboard-based application, you will often want to do a little preparation before navigation 
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender 
{ 
    // Get the new view controller using [segue destinationViewController]. 
    // Pass the selected object to the new view controller. 
} 
*/ 

@end 

這裏是我的BluetoothLEManager文件:

.h文件:

#import <Foundation/Foundation.h> 

@import CoreBluetooth; 
@import QuartzCore; 

@interface BlueToothLEManager : NSObject < CBCentralManagerDelegate, CBPeripheralDelegate> 

@property (strong, retain) CBCentralManager *mBTCentralManager; 

-(CBCentralManager*) initializeCBCentralManager; 


@end 

.m文件:

#import "BlueToothLEManager.h" 
#import "Constants.h" 

@implementation BlueToothLEManager 


-(CBCentralManager*)initializeCBCentralManager{ 
    NSLog(@"initializing CBCentral Manager"); 
    return self.mBTCentralManager = [[CBCentralManager alloc] initWithDelegate:self queue:nil]; 
} 

#pragma mark - CBCentralManagerDelegate 

// method called whenever you have successfully connected to the BLE peripheral 
- (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral 
{ 
} 

// CBCentralManagerDelegate - This is called with the CBPeripheral class as its main input parameter. This contains most of the information there is to know about a BLE peripheral. 
- (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI 
{ 
    NSLog(@"Discovered %@ at %@", peripheral.name, RSSI); 
} 

-(void)centralManagerDidUpdateState:(CBCentralManager *)central{ 
    NSLog(@"Start scan"); 

    if(central.state == CBCentralManagerStatePoweredOn){ 
     NSLog(@"Scanning for BTLE device"); 
     [central scanForPeripheralsWithServices:@[[CBUUID UUIDWithString:DEVICE_NAME]] options:@{ CBCentralManagerScanOptionAllowDuplicatesKey : @YES }]; 
    } 
} 
@end 

的問題是,應用程序總是死機/暫停。有時它會拋出一個unrecognized selector sent to instance error,但並不總是會發生。我已經檢查過,確保按鈕沒有問題,因爲當我刪除self.mCentralManager = [[BlueToothLEManager alloc]initializeCBCentralManager];時,該應用不會崩潰。

任何人都可以告訴我爲什麼這個崩潰正在發生,我該如何解決它?

回答

2

您的代碼有多個問題。現在,您並沒有保留對BluetoothLEManager實例的引用,這意味着它將在從scanButtonPressed:返回後立即釋放,但該實例仍是CBCentralManager的代理,具體取決於CBCentralManager如何存儲其委託,這可能導致崩潰或者它不會調用任何委託方法。委託通常不會被保留,所以如果實例被釋放,CBCManager將訪問無效內存,或者將它的委託設置爲零。

不要在ViewController中保留對CBCentralManager的引用,而應該保留對BluetoothLEManager實例的引用。這將解決你的第一個問題,如果你保持它的實例不會被釋放,並且CBCentralManagerDelegate方法將被正確調用。

而你正在使用錯誤的分配模式。在Objective-C中,如果調用alloc,則必須調用完整的處理,例如[[Class alloc] init][[Class alloc] initWithSomething:someThing]。以init開頭的方法必須返回它們自己的類。

這些是我現在可以發現的問題。

我有固定和現代化代碼:

BTMgr.h

#import <Foundation/Foundation.h> 

@import CoreBluetooth; 

@interface BlueToothLEManager : NSObject <CBCentralManagerDelegate, CBPeripheralDelegate> 
@property (strong, readonly) CBCentralManager *mBTCentralManager; 
@end 

BTMGr.m

#import "BlueToothLEManager.h" 
//#import "Constants.h" 

@implementation BlueToothLEManager 

- (instancetype)init { 
    self = [super init]; 
    NSLog(@"initializing BluetoothLEManager"); 
    _mBTCentralManager = [[CBCentralManager alloc] initWithDelegate:self queue:nil]; 
    return self; 
} 

#pragma mark - CBCentralManagerDelegate 

// method called whenever you have successfully connected to the BLE peripheral 
- (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral 
{ 
} 

// CBCentralManagerDelegate - This is called with the CBPeripheral class as its main input parameter. This contains most of the information there is to know about a BLE peripheral. 
- (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI 
{ 
    NSLog(@"Discovered %@ at %@", peripheral.name, RSSI); 
} 

-(void)centralManagerDidUpdateState:(CBCentralManager *)central{ 
    NSLog(@"Start scan"); 

    if(central.state == CBCentralManagerStatePoweredOn){ 
     NSLog(@"Scanning for BTLE device"); 
//  [central scanForPeripheralsWithServices:@[[CBUUID UUIDWithString:DEVICE_NAME]] options:@{ CBCentralManagerScanOptionAllowDuplicatesKey : @YES }]; 
    } 
} 
@end 

VC.h

#import <UIKit/UIKit.h> 

@interface ViewControllerIntroPage2 : UIViewController 
@property (nonatomic, strong) UIButton *scanForFetchTagsButton; 

-(IBAction)scanButtonPressed:(id)sender; 

@end 

VC.m

#import "ViewControllerIntroPage2.h" 
#import "BlueToothLEManager.h" 

@interface ViewControllerIntroPage2() 
@property (strong) BlueToothLEManager *bluetoothManager; 
@end 

@implementation ViewControllerIntroPage2 

-(IBAction)scanButtonPressed:(id)sender { 
    NSLog(@"Scan Button Clicked"); 
    if (!self.bluetoothManager) { 
     // create if it doesn't exist 
     self.bluetoothManager = [[BlueToothLEManager alloc] init]; 
    } 
    NSLog(@"Scan Done"); 
} 

@end 
+0

謝謝你的精彩解釋。我是iOS編程新手,在Android開發方面我有很強的背景,所以對我來說這是一個新點子。謝謝你的迴應。如果您知道任何能夠幫助我適應iOS的閱讀材料或信息,我不會抱怨。再次感謝。 – BlackHatSamurai 2014-12-06 01:07:58

相關問題