3

When I hit the retry button in my game, I want it to reload the MainScene. I am doing this with:

-(void)retry
{
    SKTransition *transition = [SKTransition fadeWithDuration:.4];
    MainScene *gameOver = [[MainScene alloc] initWithSize:self.size];
    [gameOver didMoveToView:self.view];
    [self.scene.view presentScene:gameOver transition:transition];
}

However, this is causing the memory/CPU usage to increase (by a lot) each time I hit retry. After about 10-20 retries, there is a noticeable lag.

I made all my SKEmitterNode and SKSpriteNode static and that fixed the memory problem, so I suspect that my sprites, emitters, etc are not being released from the memory and are being re-loaded every time I hit retry, doubling it.

I am loading the sprites/emitters like this:

@implementation MainScene {
    SKEmitterNode *_bubbleEmitter;
    SKSpriteNode *_sunglasses;
    ...
}

- (id)initWithSize:(CGSize)size
{
  if (self = [super initWithSize:size]) 
  {
     _sunglasses = [SKSpriteNode spriteNodeWithImageNamed:@"sunglasses"];
     [_sunglasses setPosition:CGPointMake(self.size.width/2,  self.size.height + 10)];
     [self addChild:_sunglasses];

     ...
  }
  return self;
}

Am I loading the sprites or the retry wrong?

Stacks
  • 110
  • 1
  • 6

1 Answers1

3

This may or may not be the cause, but it's certainly wrong to call this method yourself:

[gameOver didMoveToView:self.view];

The didMoveToView: method is sent to the scene by the SKView when you present the scene. That means this method will actually run twice.

Also verify that your scenes are deallocating properly by implementing:

-(void) dealloc
{
    NSLog(@"dealloc: %@", self);
}

Watch for the log or set a breakpoint to confirm the scene deallocates. If it isn't, check for memory leaks and retain cycles.

CodeSmile
  • 64,284
  • 20
  • 132
  • 217
  • I have no idea why that code was there, probably from testing different things out. Dealloc isn't getting called but I cannot figure out why. There is a tiny memory leak but it is related to CGPath which I read is just a bug with physicsbody. Is there another reason as to why dealloc might not be getting called? – Stacks Mar 24 '14 at 09:02
  • Retain cycles, check any strong reference to the scene, plus any node that keeps a strong reference to a parent or sibling node (those should be weak). Also, the CGPath objects you create must also be CGPathRelease(path) by you after use/assignment, that's probably not an issue with Sprite Kit. – CodeSmile Mar 24 '14 at 09:18
  • Bingo! Turned out that a NSTimer was still going and needed to be invalidated. Dealloc is being called and the problem is gone. Well almost, seems a still have a small memory leak, but the major problem is gone :) Thank you! – Stacks Mar 24 '14 at 10:07
  • Don't use NSTimer for anything timing related in Sprite Kit! Use the SKScene's update method. NSTimer may fire at undetermined times in the update loop, plus they won't pause if you pause/transition a node or scene. – CodeSmile Mar 24 '14 at 10:36
  • In iOS 8, using Swift implementation, I found in simulator the problem happens that SpriteKit scene did not unload completely. But when I tests in real device, there is no such problem. – Mahmud Ahsan Mar 01 '15 at 16:48