0

In my UIView, I have a couple of CGPath's stored in a NSArray (availablePaths).

Before anything is drawn, I create a scaled version of each CGPath and replace the old one in the array.

I get a SIGABRT in drawRect using the following code.

- (void) scaleAllPaths: (CGFloat) scaleFactor
{

 CGAffineTransform transform = CGAffineTransformMakeScale(scaleFactor, scaleFactor);
 CFIndex i;
 for(i=0;i<[availablePaths count];i++){
    id obj = [availablePaths objectAtIndex:i];
    CGPathRef oldPath = (CGPathRef)obj;
    CGMutablePathRef newPath = CGPathCreateMutable();
    CGPathAddPath(newPath, &transform, oldPath);
    [availablePaths replaceObjectAtIndex:i withObject:(id) newPath];
    CGPathRelease(newPath); // <--- causes SIGABRT in drawRect:
 }
}
-(void)drawRect:(CGRect)rect
{
...
 for (int i = 0; i < currentPathIndex; i++) {
      id obj = [availablePaths objectAtIndex:i];
      CGPathRef path = (CGPathRef)obj;
      CGContextBeginPath(context);
      CGContextAddPath(context, path);    // <---  SIGABRT
      CGContextDrawPath(context, kCGPathEOFill);

 }
...

Without the CGPathRelease(newPath) drawing works fine, but of course, I'm getting the memory leak.

roplacebo
  • 2,837
  • 2
  • 17
  • 19

2 Answers2

1

Try the solution found here for adding CGPathRefs to NSMutableArray: wrap CGPathRef inside UIBezierPath.

Edit: Looks like you can use -[UIBezierPath applyTransform:] to avoid CGPathRef in scaleAllPaths:.

- (void) scaleAllPaths: (CGFloat) scaleFactor
{
  CGAffineTransform transform = CGAffineTransformMakeScale(scaleFactor,scaleFactor);
  for (UIBezierPath *bezierPath in availablePaths){
    [bezierPath applyTransform:transform];
  }
}

- (void)drawRect:(CGRect)rect
{
  ...
  for (int i = 0; i < currentPathIndex; i++) {
    UIBezierPath *bezierPath = [availablePaths objectAtIndex:i];
    CGPathRef path = bezierPath.CGPath;
    CGContextBeginPath(context);
    CGContextAddPath(context, path);
    CGContextDrawPath(context, kCGPathEOFill);
  }
  ...
}
Community
  • 1
  • 1
Rob Bajorek
  • 6,382
  • 7
  • 44
  • 51
  • +1 for not having to create another CGMutablePathRef. Nevertheless I would like to know, what I'm actually doing wrong here. I assume, that `replaceObjectAtIndex:withObject` releases the previous object and retains the new one, correct? – roplacebo Mar 16 '13 at 11:48
1

Found out, I was releasing the CGPath object in another class, I sent it to:

-(void) setPath: (CGPathRef) pathToSet forceClosed: (BOOL) fClosed
{

  if(_path){
    CGPathRelease(_path);
  }
  _path = pathToSet;
  CGPathRetain(_path);  // <--- was missing
}

Thanks,R.

roplacebo
  • 2,837
  • 2
  • 17
  • 19
  • That makes sense, glad you figured it out. It did seem strange that it was failing, because casting any `CFPathRef` to `id` as you did should have worked. – Rob Bajorek Mar 16 '13 at 14:36