Reputation: 22559
Summary of the problem:
After I launch the app, and press "New Game", I use CCDirector
to transition to the GameScene. There, I add 32 GamePiece
objects, where these objects handle touch events as follows:
@interface GamePiece : NSObject <CCTargetedTouchDelegate>{
CCSprite* sprite;
NSInteger row;
NSInteger column;
}
//-(void)moveToRow:(NSInteger)newRow column:(NSInteger)newColumn;
-(id)initWithRow:(NSInteger)aRow column:(NSInteger)aColumn tag:(NSInteger)tag parent:(CCNode*)parent;
+(id)gamePieceWithRow:(NSInteger)aRow column:(NSInteger)aColumn tag:(NSInteger)tag parent:(CCNode*)parent;
@end
GamePiece.m:
...
- (BOOL) ccTouchBegan:(UITouch *)touch withEvent:(UIEvent *)event {
CGPoint touchLocation = [GameScene locationFromTouch:touch];
CCLOG(@"(%i, %i)", row, column); //<-----THIS!!!
//Crash never makes it here....
// Check if this touch is on the Spider's sprite.
BOOL isTouchHandled = CGRectContainsPoint([sprite boundingBox], touchLocation);
if (isTouchHandled){
id parent = sprite.parent;
[parent gamePieceSelected:self inRow:row column:column];
}
return isTouchHandled;
}
...
- (void)dealloc {
[[CCTouchDispatcher sharedDispatcher] removeDelegate:self]; //Important...
[super dealloc];
}
@end
Ok, so After I load 32 pieces, I load even more pieces using the method:
[parent gamePieceSelected:self inRow:row column:column];
as follows: (GameScene.m)
-(void)gamePieceSelected:(GamePiece*)aGamePiece inRow:(NSInteger)row column:(NSInteger)column{
[self removeChildByTag:18 cleanup:YES];
//Array of index Path!!! row = row, section = column
NSArray* moves = [self availableMovesForRow:row column:column];
for(NSIndexPath* index in moves){ //Please forgive me for using NSIndexPath!!
[GamePiece gamePieceWithRow:[index row] column:[index section] tag:18 parent:self];
}
}
So basically, when you tap a GamePiece
, I add other GamePiece
objects with tag = 18. I then use this tag to remove the "new" GamePiece
objects, and add other ones..
My problem?
After taping a GamePiece
, "new" game pieces appear appropriately, but it crashes after I tap more than once! I mean, I tap a GamePiece
, the new gamePieces appears. Then, if I tap another GamePiece
, I put my hand on my heart waiting for a crash.. Sometimes it crashes, other times it doesn't... The third time, fourth, fifth ... etc. I managed a highscore of 10 taps before it crashed :P ... so random....
My theory:
See the comment line //<------THIS
, the CCLOG
gets called an arbitrary number of times each time I tap the screen until it finds the GamePiece
that satisfies the if statement, which is kinda normal, since I have many GamePiece
objects loaded at the same time..
When it crashes (without any stack trace or messages), this CCLOG
gets called a few times, and never makes it inside the if statement!! I think it is because it's trying to send a touch message to a GamePiece
that has been removed by removeChildWithTag:
.. But I already call [[CCTouchDispatcher sharedDispatcher] removeDelegate:self];
in dealloc, which leads to a very important fact:
If I wait a few seconds after taping a GamePiece
before I tap another one, I have a higher chance of not crashing!!
It feels like I am giving it time to call dealloc, and remove the touch delegate...
EDIT:
It occurred to me to add a CCLOG
in dealloc, and it was never called...
END EDIT
And am not sure if this is obvious, but if I DON'T remove the newly added GamePieces, the game never crashes... But I need to remove them :P
Please help, I have been fighting this issue for days >.
Upvotes: 2
Views: 633
Reputation: 22559
THIS!!:
[[CCTouchDispatcher sharedDispatcher] addTargetedDelegate:self priority:-1 swallowsTouches:YES]; //Important...
was the biggest mistake EVER!!
This neat piece of code:
[[CCTouchDispatcher sharedDispatcher] removeDelegate:self];
actually retains the delegate... and I never reach dealloc, and never removeDelegate from the touch dispatcher and cause a catastrophe ...
EDIT:
Ok, someone wants to know where I ended up removing the delegate! And I am surprised that I didn't mention that!
- (void)onExit {
[[CCTouchDispatcher sharedDispatcher] removeDelegate:self];
// Never forget this!!
[super onExit];
}
Upvotes: 2