I am using the IOBluetooth framework on Mac OSX to do device discovery. I have added some NSLog()
inside the callback functions, so I know the progress.
If I compile the code with gcc on command line like this, everything works fine (source file f.m
, output a
):
gcc -o a f.m -framework Foundation -framework IOBluetooth
However, if I add a -fobjc-arc
flag to ensure Automatic Reference Counting:
gcc -fobjc-arc -o a f.m -framework Foundation -framework IOBluetooth
Compilation is still ok, but executing the file ./a
resulting in either a seg fault:
2017-06-21 22:06:23.150 a[718:17437] Program started ...
Segmentation fault: 11
or hanging there forever:
2017-06-21 22:06:27.070 a[721:17809] Program started ...
Sometimes it hangs, sometimes it seg faults. The behavior is inconsistent. If I don't add the -fobjc-arc
flag, everything works as expected (on the surface at least).
So my question is, why does it behave the way it does after I add the -fobjc-arc
flag?
In case it helps, the complete source file is here:
#import <IOBluetooth/IOBluetooth.h>
@interface InquiryDelegate : NSObject <IOBluetoothDeviceInquiryDelegate>
@end
@implementation InquiryDelegate
-(void)deviceInquiryStarted:(IOBluetoothDeviceInquiry *)sender
{
NSLog(@"Inquiry started ...");
}
-(void)deviceInquiryDeviceFound:(IOBluetoothDeviceInquiry *)sender
device:(IOBluetoothDevice *)device
{
NSLog(@"Device found");
}
-(void)deviceInquiryComplete:(IOBluetoothDeviceInquiry *)sender
error:(IOReturn)error
aborted:(BOOL)aborted
{
NSLog(@"Inquiry complete");
}
-(void)deviceInquiryUpdatingDeviceNamesStarted:(IOBluetoothDeviceInquiry *)sender
devicesRemaining:(uint32_t)devicesRemaining
{
}
-(void)deviceInquiryDeviceNameUpdated:(IOBluetoothDeviceInquiry *)sender
device:(IOBluetoothDevice *)device
devicesRemaining:(uint32_t)devicesRemaining
{
}
@end
int main(int argc, const char* argv[]) {
@autoreleasepool {
NSLog(@"Program started ...");
IOBluetoothDeviceInquiry* di = [[IOBluetoothDeviceInquiry alloc]
initWithDelegate:[[InquiryDelegate alloc] init]];
[di start];
[[NSRunLoop currentRunLoop] run];
}
}
In case anyone is wondering, my goal is to produce a dynamic library for use in a JNI project, with no GUI involved. This is my attempt to gain some experience with the way Bluetooth is done on Mac, and get myself acquainted with Objective-C. I am coming from a Linux background, so prefer to stay on the command line if possible.
Thanks in advance.
Thanks to hints given by commenters above, I am able to solve the problem by adding a strong reference to the delegate object:
InquiryDelegate* g = [[InquiryDelegate alloc] init];
IOBluetoothDeviceInquiry* di = [[IOBluetoothDeviceInquiry alloc]
initWithDelegate:g];
Thanks to both @Willeke and @Ssswift.