CBCentralManager and Automatic Reference Counting - c++

I have two applications which are very similar in their BLE functionality however one scans correctly & discovers peripherals where other does not.
They both report no problems initializing their pointer to CBCentralManager & checking that it's on & functional, but one goes on to discover & be able to connect to a device & the other does not.
In the one that doesn't work the call to scanForPeripheralsWithServices goes off without a hitch but the didDiscoverPeripheral callback is never triggered. The biggest difference that i can think of is that one project uses pure Objective-C & ARC whereas the other uses a mix of Objective-C & C++ and does not use automatic reference counting.
Could this be the source of the problem ? If so, is there a way around it? I have been able to work with CoreBluetooth in the past without ARC but it might have changed without my being able to parse that from the docs.
In the event that it's not ARC, the two calls to scanForPeripheralsWithServices are shown below:
functional
- (int) findBLEPeripherals:(int) timeout
{
NSLog(#"start finding");
if (self.CM.state != CBCentralManagerStatePoweredOn)
{
NSLog(#"CoreBluetooth not correctly initialized !");
NSLog(#"State = %d (%s)\r\n", self.CM.state, [self centralManagerStateToString:self.CM.state]);
return -1;
}
[NSTimer scheduledTimerWithTimeInterval:(float)timeout target:self selector:#selector(scanTimer:) userInfo:nil repeats:NO];
[self.CM scanForPeripheralsWithServices:[NSArray arrayWithObject:[CBUUID UUIDWithString:#RBL_SERVICE_UUID]] options:nil];
NSLog(#"scanForPeripheralsWithServices");
return 0; // Started scanning OK !
}
non-functional
- (void)startScan
{
NSLog(#"startScan");
isScanning = true;
NSDictionary *options = nil;
didUpdateDiscoveredDeviceFlag = [delegate respondsToSelector:#selector(didUpdateDiscoveredRFduino:)];
if (didUpdateDiscoveredDeviceFlag) {
options = [NSDictionary dictionaryWithObject:[NSNumber numberWithBool:YES]
forKey:CBCentralManagerScanOptionAllowDuplicatesKey];
}
[devices removeAllObjects];
if (self.central.state != CBCentralManagerStatePoweredOn)
{
NSLog(#"CoreBluetooth not correctly initialized !");
// NSLog(#"State = %d (%s)\r\n", self.central.state, [self centralManagerStateToString:self.central.state]);
}
[NSTimer scheduledTimerWithTimeInterval:(float)60 target:self selector:#selector(scanTimer:) userInfo:nil repeats:NO];
[self.central scanForPeripheralsWithServices:[NSArray arrayWithObject:[CBUUID UUIDWithString:#RBL_SERVICE_UUID]] options:#{ CBCentralManagerScanOptionAllowDuplicatesKey : #YES }];
if (didUpdateDiscoveredDeviceFlag) {
[self startRangeTimer];
}
}
And the relevant parts of the two header files:
functional
#interface BLE : NSObject <CBCentralManagerDelegate, CBPeripheralDelegate> {
}
#property (nonatomic,assign) id <BLEDelegate> delegate;
#property (strong, nonatomic) NSMutableArray *peripherals;
#property (strong, nonatomic) NSMutableArray *peripheralsRssi;
#property (strong, nonatomic) CBCentralManager *CM;
#property (strong, nonatomic) CBPeripheral *activePeripheral;
non-functional
#interface BLEDeviceManager : NSObject <CBCentralManagerDelegate>
{
}
+ (BLEDeviceManager *)sharedDeviceManager;
#property (strong, nonatomic) CBCentralManager *central;
Any advice much appreciated!

So this is a bit silly but a reboot of the phone + clean/build fixed everything. I suspect that the two applications weren't playing nice with one another in releasing the CBCentralManager handle but that's just a guess. I'm not deeply familiar with CoreBluetooth or with Objective C to be honest so my guesses aren't all that well informed.

Related

Subclassed CCSpriteBatchNode object is nil

I subclassed CCSpriteBatchNode to make an object that conforms to NSCoding. I was mainly interested in the string name of the CCSpriteBatchNode. After setting break points I realized that the object's string name is always nil. I have a feeling it that my overridden methods might be a contributing factor but I'm not really sure about that. Please see relevant code below:
SpriteBatchNode interface:
#interface SpriteBatchNode: CCSpriteBatchNode {
NSString* batchImageName;
}
SpriteBatchNode implementation:
const NSUInteger defCapacity = 29;
#implementation SpriteBatchNode
#synthesize batchImageName;
+(id)batchNodeWithFile:(NSString*) imageFile
{
return [[self alloc] initWithFile:imageFile capacity:defCapacity];
}
-(id)initWithFile:(NSString *)fileImage {
self = [super initWithFile:fileImage capacity:defCapacity];
if (!self) return nil;
batchImageName = fileImage;
return self;
}
-(id)initWithCoder:(NSCoder *)aDecoder
{
NSString* spriteBatchNodeFileImage = [[aDecoder decodeObjectForKey:#"batchImageName"] copy];
self = [super initWithFile:spriteBatchNodeFileImage capacity:defCapacity];
if (!self) return nil;
return self;
}
-(void)encodeWithCoder:(NSCoder *)aCoder
{
[aCoder encodeObject:batchImageName forKey:#"batchImageName"];
}
#end
If you aren't using ARC I see two problems here:
batchImageName string is not retained
batchNodeWithFile: is not sending autorelease to the returned instance
Other than that you're using an unusual init style, the common style is this:
if (self)
{
batchImageName = fileImage;
}
return self;
Checking self for nil, then returning nil if it is, is somewhat redundant.

error when returning to game menu after game over [duplicate]

I'm threeaing some tasks like this :
RootViewController
- (void)viewDidLoad {
[NSThread detachNewThreadSelector:#selector(findSomething) toTarget:self withObject:nil];
}
- (void) findSomething {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
doMoreThings
[pool release];
}
- (void) doMoreThings {
doMoreMoreMoreThings on different objects
}
- (void) foundSomething:(NSFoundThing*)foundObj {
do your stuff
}
oneObject
- (void) doMoreMoreMoreThings {
do things
[self performSelectorOnMainThread:#selector(foundSomething:) withObject:thingFound waitUntilDone:NO];
}
gives
-[KMLParser foundSomething:]: unrecognized selector sent to instance 0x5888080
What is the problem ?
The threading is irrelevant. Some of the code you're not showing us is making it so you are sending the foundSomething: selector to an object that doesn't handle that message. Route the message to an object that does handle it, and your problem will go away.
See also "Unrecognized selector sent to instance".

Get notification's from NSNotificationServer in C++ program

I'm creating a simple C++ application with cmake on Mac.
There is a main in C++ source code file, that create C++ class. Inside this class I'm allocating objective C object, that adding itself to observers in NSNotificationCenter. And I'm not receiving those notifications.
There is a code:
Notifications.h
class LaunchNotification {
public:
LaunchNotification();
virtual ~LaunchNotification();
void StartNotifications();
void StopNotifications();
private:
void *monitor;
};
Notifications.mm
#interface Monitor : NSObject
-(id) init;
-(void) appLaunchedNotification :(NSNotification *) notification;
-(void) appTerminatedNotification :(NSNotification *) notification;
#end
#implementation Monitor
- (id) init
{
self = [super init];
if (self)
{
count = 0;
NSNotificationCenter *notCenter = [[NSWorkspace sharedWorkspace] notificationCenter];
[notCenter addObserver : self
selector:#selector(appLaunchedNotification:)
name:NSWorkspaceDidLaunchApplicationNotification
object:nil];
[notCenter addObserver : self
selector:#selector(appTerminatedNotification:)
name:NSWorkspaceDidTerminateApplicationNotification
object:nil];
}
return self;
}
- (void) appLaunchedNotification : (NSNotification *) notification
{
NSString *path = [[notification userInfo]objectForKey: #"NSApplicationPath"];
}
- (void) appTerminatedNotification : (NSNotification *) notification
{
NSString *path = [[notification userInfo]objectForKey: #"NSApplicationPath"];
}
- (void) dealloc
{
NSNotificationCenter *notCenter = [[NSWorkspace sharedWorkspace] notificationCenter];
[notCenter removeObserver : self];
[super dealloc];
}
#end
LaunchNotification::LaunchNotification() : monitor(NULL)
{}
LaunchNotification::~LaunchNotification()
{
StopNotifications();
}
void LaunchNotification::StartNotifications()
{
if (NULL == monitor)
{
monitor = [[Monitor alloc] init];
}
}
void LaunchNotification::StopNotifications()
{
if (NULL != monitor)
{
[(id)monitor release];
}
}
You need a run loop because otherwise, NSWorkspace has no mechanism to gain control of your application's thread in order to post notifications.
While the docs say run loops are automatically created, they are not automatically executed. Think about it: how can a thread be simultaneously running your code and running the code in the run loop?
Any tasks that you need to do while you are monitoring the notification centre need to be done in the context of runloop events e.g. on an NSTimer event, or you need a separate thread for that other stuff.

cocos2d-iphone: init method does not work properly

I'm studying Strougo/Wenderlich tutorial (space Viking project). I got troubles with chapter 4.
In RadarDish.m:
-(void)initAnimations
{
[self setTransmittingAnim: [self loadPlistForAnimationWithName:#"transmittingAnim" andClassName:NSStringFromClass([self class])]];
}
-(void)changeState:(CharacterStates)newState {
[self stopAllActions];
id action = nil;
[self setCharacterState:newState];
switch (newState) {
.
.
case kStateIdle:
action = [CCAnimate actionWithAnimation:transmittingAnim
restoreOriginalFrame:NO];
break; }
if (action != nil) {
[self runAction:action];
}
}
-(id)init
{
self=[super init];
if (self!=nil) {
.
.
[self initAnimations];
.
.
}
return self;
}
Exact the same code as in the tutorial. Failure:
*** Assertion failure in -[CCAnimate initWithAnimation:], /Users/macowner/Documents/examples/SpaceViking/SpaceViking/libs/cocos2d/CCActionInterval.
Using debugger with breakpoints, i noticed that value of transmittingAnim = nil.
So, if i put line with
[self setTransmittingAnim:
[self loadPlistForAnimationWithName:#"transmittingAnim" andClassName:NSStringFromClass([self class])]];
into case of
-(void)changeState then animation works correctly.
Why [self initAnimations] from (id)init is not called?
Im using cocos2d v.2 templates.
Great thanks in advance.
I had problems because I have been building project using cocos 2d v.2.0, while tutorial is based on cocos 2d templates v.1.x.x If you are going to follow the book "Learning Cocos2D", I strongly recommend you loading cocos2d-iphone version 1.0.1. Here is the link download cocos2d 1.x.x branch
if you still want to use latest cocos2d templates, I can give you some advice:
Follow the instructions in this link cocos2d v2.0 migration guide
You are going to have a lot of deprecations and changes to fix, so use this link to understand how to fix those deprecations and changes.
Now few words about the solution of the problem I mentioned here. In each of the GameObjects, EnemyObjects, and PowerUps, I added a method to override initWithFrameName.
-(id) initWithSpriteFrameName:(NSString*)frameName{
if ((self=[super init])) {
if ((self = [super initWithSpriteFrameName:frameName])) {
CCLOG(#"### RadarDish initialized");
[self initAnimations]; // 1
characterHealth = 100.0f; // 2
gameObjectType = kEnemyTypeRadarDish; // 3
[self changeState:kStateSpawning]; // 4
}
}
return self;
}
    This allows the GameObject and GameCharacter init methods to run before the CCSprite's initWithSpriteFrameName method to run.
    
    The Viking GameObject had to have a slightly different solution because it is initialized with initWithSpriteFrame rather than initWithSpriteFrameName. However, the override implementation is basically the same as the example of RadarDish above.

cocos2d: Subclassing CCMenuItem triggers a lot of "removeChildByTag: child not found!"

I am trying to subclass a CCMenuItem using the following code:
GenericButton.h
#import <Foundation/Foundation.h>
#import "cocos2d.h"
#interface GenericButton : CCMenuItemSprite {
}
+(id) itemwithTitle:(NSString*)title withBGColor: (ccColor3B) bgColor andFGColor:(ccColor3B)fgColor;
#end
GenericButton.m
#import "GenericButton.h"
#import "HelpfulClasses.h"
#implementation GenericButton
+(id) itemwithTitle:(NSString*)title withBGColor: (ccColor3B) bgColor andFGColor:(ccColor3B)fgColor{
CCSprite*genericButtonBG = [CCSprite spriteWithSpriteFrameName:#"genericButtonBG.png"];
genericButtonBG.color=bgColor;
CCSprite*genericButtonBGPressed = [CCSprite spriteWithSpriteFrameName:#"genericButtonBGPressed.png"];
genericButtonBGPressed.color=bgColor;
CCMenuItemSprite*button = [CCMenuItemSprite itemWithNormalSprite:genericButtonBG selectedSprite:genericButtonBGPressed];
CCSprite*fgButton = [CCSprite spriteWithSpriteFrameName:#"genericButton.png"];
fgButton.color=fgColor;
[button addNodeInMiddleOfParent:fgButton];
CCLabelBMFont *buttonTitle = [CCLabelBMFont labelWithString:title fntFile:#"font.fnt"];
if ([title length]>7) {
buttonTitle.scale=0.85;
}
buttonTitle.color=ccYELLOW;
[fgButton addNodeInMiddleOfParent:buttonTitle];
return button;
}
// on "dealloc" you need to release all your retained objects
- (void) dealloc
{
// in case you have something to dealloc, do it in this method
// in this particular example nothing needs to be released.
// cocos2d will automatically release all the children (Label)
// don't forget to call "super dealloc"
[super dealloc];
}
#end
But whenever I am using GenericButton*button = [GenericButton item....], in a CCScene, there is a lot of"removeChildByTag: child not found!" showing on the console. Am I doing something wrong?
Cheers
After two months you've probably figured this out yourself. Doesn't this website have a way to PM somebody? So sorry if I resurrect and old thread.
You are not including all your code for this class. However, I can point out something I saw that is an issue and could possibly be the source of your problem. In your class method you are creating and returning a pointer to "CCMenuItemSprite" called "button". This should be a pointer to your class "GenericButton".