Search code examples
iosobjective-csprite-kitskshapenodecgpathref

SKShapeNode and CGPathRef EXC_BAD_ACCESS


I am trying to dynamically draw curves along a path in an attempt to represent mountains.

I have a function that returns a CGPathRef, which is a C pointer to a struct.

-(CGPathRef)newPath
{
    CGMutablePathRef mutablePath = CGPathCreateMutable();
    //inserting quad curves, etc
    return mutablePath;
} 

I then pass these CGPathRefs around by wrapping them in a UIBezierPath.

-(NSArray*)otherFunction
{
    CGPathRef ref = [self newPath];
    UIBezierPath *path = [UIBezierPath bezierPathWithCGPath: ref];
    NSArray* paths = @[path];
    CGPathRelease(ref);
    return paths;
}

I then take the returned array of paths and display them to the screen using an SKShapeNode.

SKShapeNode *node = [SKShapeNode new];

NSArray* paths = [self otherFunction];
CGPathRef ref = [[paths firstObject] CGPath];

node.path = ref; 
node.fillColor = [UIColor orangeColor];
node.lineWidth = 2;

And finally.

[self addChild:node];
CGPathRelease(node.path);

After I repeat this sequence of action a few times my program breaks and shows me.

UIApplicationMain with EXC_BAD_ACCESS code = 2.

I understand there is a memory leak.

My question is how do I handle releasing the CGPathRef when I end up passing it through a few functions and wrapping it in another class?

I updated the code and am now receiving a EXC_I386_GPFLT error.


Solution

  • I see three problems.

    1. I'm not very familiar with SKShapeNode, but from the documentation it looks like it just uses the path you give it without copying it (unlike UIBezierPath). In that case, you need to copy the path out of the UIBezierPath's CGPathRef, because otherwise it will be deallocated once the UIBezierPath is released. For example:

      SKShapeNode *node = [SKShapeNode new];
      CGPathRef pathCopy = CGPathCreateCopy(/* path from other function unwrapped */);
      node.path = pathCopy;
      ...
      

      You may possibly need to deallocate that path when you're done with the shape node:

      CGPathRelease(node.path);
      
    2. It looks like you have some memory leaks in the code you posted: you're creating CGPathRefs in newPath, copying them to a UIBezierPath in otherFunction, and never deleting them. That would not cause your problem, but it may cause others down the road. :)

    3. I'd be careful naming methods with a prefix of new since that has some meaning to Objective-C (see here). Try createPath instead.