0

I'm trying to write my little app and experiencing some memory management problems. At first, I have Game singleton object with property:

//Game.h
@interface Game : NSObject

@property (nonatomic, retain) MapBuildingsLayer *mapBuildingsLayer;

+(Game *) game;
-(BOOL) addObject:(NSString *) objName At:(CGPoint) pt;

@end

where MapBuildingsLayer is just cocos2d CCLayer instance

//Game.m
@implementation Game
@synthesize mapBuildingsLayer = _mapBuildingsLayer;

static Game *instance = nil;

+ (Game *)game {
    @synchronized(self) {
        if (instance == nil) {
            instance = [[Game alloc] init];
        }
    }
    return instance;
}

-(BOOL) addObject:(NSString *)objName At:(CGPoint)pt
{
    if([objName isEqualToString:OBJ_TYPE_PIT])
    {
        if([[Game game].mapBuildingsLayer addPitAt:pt]) //app crashes here
        {
            [self toggleConstructionMode];
            return YES;
        }
    }
    return NO;
}

@end

In MapBuildingsLayer.m's init method I use Game's mapBuildingsLayer property to store a reference to this CCLayer instance in my singleton (for future use in other methods):

//MapBuildingsLayer.m
@implementation MapBuildingsLayer

-(id) init
{
    if( (self=[super init])) {
        [Game game].mapBuildingsLayer = self;
    }
    return self;
}

When I call Game's addObject:objName At: method, my app crashes with EXC_BAD_ACCESS. How I must declare property in Game singleton to use it from other places in my app's lifetime?

3 Answers3

0

No where in your code i am seeing your mapBuildingsLayer initialized. I hope before returning your instance you should also do

instance.mapBuildingsLayer = [CCLayer alloc] init];
Saran
  • 6,274
  • 3
  • 39
  • 48
  • Of course I have the following line: `MapBuildingsLayer *buildings = [MapBuildingsLayer node];` in my code. My `MapBuildingsLayer` instance is initialized and working properly (catching touch events for example). – Anton Rassadin Sep 17 '11 at 13:32
  • @Saran: Although you are right, this is probably not the cause of the crash. If it's not initialized it will be nil, and sending messages to nil won't cause a crash. By the way, this code should be more along the lines of `instance.mapBuildingsLayer = [[[MapBuildingsLayer alloc] init] autorelease]`; – Rengers Sep 17 '11 at 13:33
0

You typically don't use the singleton in the class itself, try changing

        if([[Game game].mapBuildingsLayer addPitAt:pt]) //app crashes here

to

        if([self.mapBuildingsLayer addPitAt:pt]) //app crashes here

You should be using [Game game] external to the class to get into the singleton instance of your class and call its methods, but internal to the class you would just refer to it as self like normal.

Typically if you're going to use a game singleton this isn't how you'd use it. Try thinking of it like this with a giant state machine, Create a CCScene subclass which will initialize all of your respective CCLayer subclasses and control them. Then from the statemachine you can load the appropriate initializing its scene and that will create everything under it.

In your applicationDidFinishLaunching method you simply have your singleton object load your first scene. I'd really recommend checking out the Learning Cocos2d Book as it covers this singleton state engine very well and I think would clear up all your questions.

Bottom line is have the state engine load the scene which loads the layers.

crackity_jones
  • 1,077
  • 2
  • 13
  • 16
  • Thanks for the advice! But changing `[Game game]` to `[self]` didn't fixed crash. – Anton Rassadin Sep 17 '11 at 13:46
  • Guarantee your mapBuildingsLayer property is nil at this point. – crackity_jones Sep 17 '11 at 14:00
  • Yes, this property initionally is `nil`, then after initialization of `MapBuildingsLayer` it's set to proper address (I've just checked it through debug). I mean, my instance of `MapBuildingsLayer` have address `0xAABBCC` for example and value of `[Game game].mapBuildingsLayer` also set to `0xAABBCC` at the moment of crash. – Anton Rassadin Sep 17 '11 at 14:17
0

I think the way you are assigning the mapBuildingsLayer is wrong. Remove [Game game].mapBuildingsLayer = self from your MapBuildingsLayer init method and instead add the following inside Game init method:

self.mapBuildingsLayer = [[MapBuildingsLayer alloc] init] autorelease];

now it is initialized inside your singleton init method so you can access it simply as [Game game].mapBuildingsLayer anywhere outside the Game class. If this doesnt work try posting what addPitAt: does.

hope this helps

KDaker
  • 5,899
  • 5
  • 31
  • 44