If I run this code in a SKScene sublass init method
for (int i = 0; i < 100; i++) {
SKShapeNode *shape = [SKShapeNode node];
shape.antialiased = NO;
CGMutablePathRef path = CGPathCreateMutable();
CGPathAddEllipseInRect(path, NULL, CGRectMake(arc4random()%320, arc4random()%320, 10, 10));
shape.path = path;
[shape setStrokeColor:[UIColor blackColor]];
CGPathRelease(path);
[self addChild:shape];
[shape removeFromParent];
}
and everytime I run this code in my SKView controlling controller
SKView * skView = (SKView *)self.view;
// Create and configure the scene.
SKScene * scene = [ZTMyScene sceneWithSize:skView.bounds.size];
scene.scaleMode = SKSceneScaleModeAspectFill;
// Present the scene.
[skView presentScene:scene];
my memory usage grow until the memory is full and crashes. This does not happen if I use a SKSpriteNode. Has anyone a fix for this?
Summary: I create the sprite kit template project, add a lot of SKShapeNodes and replace the old SKScene with a new one.
I added a sample project to github https://github.com/zeiteisen/MemoryTest
I became aware of this issue while reading another post. I messed around with SKShapeNode
a bit and indeed verified the memory leak issue pinpointed here.
While doing that, I had an idea...
Not really a new idea, more of a repurposed one. This wonderful idea actually allowed me to use SKShapeNodes to my hearts content :)
POOLING
Yep... I just created a pool of SKShapeNodes that I reused as needed. What a difference that makes :)
You simply redefine the path whenever needed, when done using return to your pool, and it'll be waiting there for you to play with again at a later time.
Create a ivar or property NSMutableArray
in your SKScene
called pool and create it when you init the SKScene
. You can either populate the array with your shape nodes during init, or you can create them as needed.
This is something quick method I created for grabbing a new node from the pool :
-(SKShapeNode *)getShapeNode
{
if (pool.count > 0)
{
SKShapeNode *shape = pool[0];
[pool removeObject:shape];
return shape;
}
// if there is not any nodes left in the pool, create a new one to return
SKShapeNode *shape = [SKShapeNode node];
return shape;
}
So wherever in the scene you need a SKShapeNode you'd do this :
SKShapeNode *shape = [self getShapeNode];
// do whatever you need to do with the instance
When you are done using the shape node, just return it to the pool and set the path to NULL, for example :
[pool addObject:shape];
[shape removeFromParent];
shape.path = NULL;
I know it's a workaround and not an ideal solution, but certainly this is a very viable workaround for anyone wanting to use a large number of SKShapeNodes and not bleed memory.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With