Reputation: 7117
I am making a simple game project involving the use of Cocos2d. Now as defined by Ray Wenderlich's example, i have completed the whole tutorial but added an extra bit of code myself to check total number of melons, when they reach 3, i replace screen with "You Win" screen to notify the user that he has won using [[CCDirector sharedDirector] replaceScene:gameoverscreen];
.
The problem is that i get EXC_BAD_ACCESS everytime i call this from ccTouchEnded
coz my condition is checked here. But the same thing works if i use [[CCDirector sharedDirector] pushScene:gameoverscreen];
Cant understand what the problem is!!
the code for gameoverscreen screen is:
#import "GameOverScene.h"
#import "HelloWorldScene.h"
@implementation GameOverScene
@synthesize _layer = layer;
- (id)init {
if ((self = [super init])) {
self._layer = [GameOverLayer node];
[self addChild:layer];
}
return self;
}
- (void)dealloc {
[layer release];
layer = nil;
[super dealloc];
}
@end
@implementation GameOverLayer
@synthesize _label = label;
-(id) init
{
if( (self=[super initWithColor:ccc4(255,255,255,255)] )) {
CGSize winSize = [[CCDirector sharedDirector] winSize];
self._label = [CCLabel labelWithString:@"" fontName:@"Arial" fontSize:32];
label.color = ccc3(0,0,0);
label.position = ccp(winSize.width/2, winSize.height/2);
[self addChild:label];
[self runAction:[CCSequence actions:
[CCDelayTime actionWithDuration:3],
[CCCallFunc actionWithTarget:self selector:@selector(gameOverDone)],
nil]];
}
return self;
}
- (void)gameOverDone {
[[CCDirector sharedDirector] replaceScene:[[[HelloWorld alloc] init] autorelease]];
}
- (void)dealloc {
[label release];
label = nil;
[super dealloc];
}
@end
and the Header file of GameoverScene contains the following!
#import "cocos2d.h"
@interface GameOverLayer : CCColorLayer {
CCLabel *label;
}
@property (nonatomic, retain) CCLabel *_label;
@end
@interface GameOverScene : CCScene {
GameOverLayer *layer;
}
@property (nonatomic, retain) GameOverLayer *_layer;
@end
i call the scene from HelloWorld class using the following syntax!
GameOverScene *gameoverscene = [GameOverScene node];
[gameoverscene._layer._label setString:@"You WON!"];
[[CCDirector sharedDirector] pushScene:gameoverscene];
Upvotes: 1
Views: 5155
Reputation: 41
I also account with such thing,the reason for it may be you release something that are autorelease,so you can try it again by not to release some object in the dealloc method!
Upvotes: 0
Reputation: 64477
I see several issues in your code.
One is the CCLabel object, you initialize it as autorelease object using cocos2d's static initializer:
self._label = [CCLabel labelWithString:@"" fontName:@"Arial" fontSize:32];
But in the dealloc method you release it even though its an autorelease object:
- (void)dealloc {
[label release];
label = nil;
[super dealloc];
}
You should not release the label since it is set to autorelease by cocos2d! This is a guaranteed crash!
Then you make things more complicated than needed:
[[CCDirector sharedDirector] replaceScene:[[[HelloWorld alloc] init] autorelease]];
The alloc/init/autorelease is completely superfluous because you can simply write [HelloWorld scene] if the HelloWorld class has a +(id) scene method (it normally should). If not, then use [HelloWorld node]. Always prefer cocos2d's static autorelease initializers before using alloc/release on cocos2d objects. The only time you ever need to alloc a cocos2d class is when you explicitly don't add it as a child to some other node, which is rare.
Finally, this is very bad style:
-(id) init
{
if( (self=[super initWithColor:ccc4(255,255,255,255)] )) {
If the super implementation of initWithColor calls [self init] - which is often the case and even if not, could change with future releases of cocos2d - it would call your implementation of init, resulting in an endless loop (stack overflow). To fix this simply either rename your init method or call [super init] and provide the parameters some other way, usually there will be a property or setter method to do so.
And a minor issue: Apple advises against using leading underscores as member variable prefix. In fact, many other compiler vendors advice against that too since often system internal variables use one or two underscores as prefix. The cocos2d style with trailing underscores is preferred which would have you write label_ instead of _label.
Upvotes: 2
Reputation: 1306
The general rule when it comes to memory dealing is to release whatever you alloced or retained. In your case you are instantiating a CCLabel object with a convenience method (thus, not calling alloc) and you are not retaining it. So, that [label release] in your dealloc method must not be there in this case.
Upvotes: 0
Reputation: 5589
EXEC_BAD_ACCESS
means you are using data that has been released. Does the youwin
scene use data from the current scene? If so, it needs to retain
the data. When replaceScene:
is called, the current scene is not held in memory but when pushScene:
is called, both scenes remain in memory.
EDIT:
Let's say you have two scenes, A
and B
. When you call pushScene:
, A
continues to exist in memory and B
is added. When you call replaceScene:
, A
is removed and no longer exists, only the B
scene. That is why A
's data would disappear, but only when replacing.
Upvotes: 1