3

I'm trying to use a loop to build a variable number of CGMutablePathRef's in order to draw a variable number of filled in wedges on a circle. For some reason, though, at the end of my loop my array returns with only one object. Here is the method I'm using to construct the array:

+ (NSMutableArray *)pathForCircleWithRect:(CGRect)rect numOfWedges:(NSUInteger)num
{
CGPoint center = CGPointMake(CGRectGetMidX(rect), CGRectGetMidY(rect));
CGFloat radius = rect.size.width / 2;
CGFloat angle = RADIANS(360) / num;

CGFloat startAngle = 0;
CGFloat endAngle = startAngle + angle;

NSMutableArray *paths = [NSMutableArray array];

for (int x = 0; x < num; x++);
{
    CGMutablePathRef path = CGPathCreateMutable();
    CGPathMoveToPoint(path, NULL, center.x, center.y);
    CGPathAddArc(path, NULL, center.x, center.y, radius, startAngle, endAngle, 0);
    CGPathAddLineToPoint(path, NULL, center.x, center.y);

    [paths addObject:(id)path];
    startAngle = endAngle;
    endAngle = startAngle + angle;
}

return paths;
}

Edit New attempt using UIBezierPath's:

+ (NSMutableArray *)pathForCircleWithRect:(CGRect)rect numOfWedges:(NSUInteger)num
{
CGPoint center = CGPointMake(CGRectGetMidX(rect), CGRectGetMidY(rect));
CGFloat radius = rect.size.width / 2;
CGFloat angle = RADIANS(360) / num;

CGFloat startAngle = 0;
CGFloat endAngle = startAngle + angle;

NSMutableArray *paths = [NSMutableArray array];

for (int x = 0; x < num; x++);
{
    CGMutablePathRef path = CGPathCreateMutable();
    CGPathMoveToPoint(path, NULL, center.x, center.y);
    CGPathAddArc(path, NULL, center.x, center.y, radius, startAngle, endAngle, 0);
    CGPathAddLineToPoint(path, NULL, center.x, center.y);

    [paths addObject:[UIBezierPath bezierPathWithCGPath:path]];
    startAngle = endAngle;
    endAngle = startAngle + angle;
}

return paths;
}

The code that calls this function:

- (void)drawRect:(CGRect)rect
{
int num = 18;
NSMutableArray *paths = [WheelView pathForCircleWithRect:rect numOfWedges:num];
NSMutableArray *colors = [WheelView colorsForCircleWithNumOfWedges:num];
CGContextRef context = UIGraphicsGetCurrentContext();

for (int x = 0; x < num; x++)
{
    CGContextSetFillColorWithColor(context, (CGColorRef)[colors objectAtIndex:x]);
    CGContextSaveGState(context);
    CGMutablePathRef wedgePath = (CGMutablePathRef)[paths objectAtIndex:x];
    CGContextAddPath(context, wedgePath);
    CGContextDrawPath(context, kCGPathFill);
    //CGContextClip(context);
    CGContextRestoreGState(context);
}
}
Chiubaka
  • 801
  • 2
  • 11
  • 27
  • 2
    Two comments: 1) You're leaking the paths. You're creating them, then adding them to an array, and then not releasing then. 2) CGPathRef isn't toll-free bridged with any Objective-C objects. It's quite possible that they will, in fact, work because the base class used by CFTypeRefs translates `-retain` into `CFRetain()`, but strictly speaking, it shouldn't. You should wrap your `CFPathRef`s with `UIBezierPath*` objects. – Lily Ballard Sep 11 '11 at 09:40
  • Do you actually call the method with `numOfWedges:` > 1 ? – DarkDust Sep 11 '11 at 09:45
  • Yup, I'm entering it in with 18. I've inserted breakpoints in the loop to ensure that x does indeed reach 18. The object that is returned is only the first path. – Chiubaka Sep 11 '11 at 10:43
  • @Kevin Ballard Yeah, I figured it was a better idea to leak the paths than to find out I was releasing them too early. I'm actually just converting those paths right back to CGMutablePathRef's when I pull them out of the array... is there a better array wrapper I could use there? – Chiubaka Sep 11 '11 at 10:54
  • @Kevin Ballard I tried to wrap my paths in `UIBezierPath` objects, but I'm still having the same problem. I've updated the question with the new code. – Chiubaka Sep 11 '11 at 11:06
  • For the record, you're still leaking the CGMutablePathRefs. – Lily Ballard Sep 11 '11 at 20:48
  • @Kevin Ballard, yeah, but I'm pretty sure that's not the underlying problem right now... – Chiubaka Sep 12 '11 at 00:18
  • @KevinBallard - Revisiting this, Ken Ferry indicates that the casting to (id) here of the CFType is fully supported behavior: http://stackoverflow.com/a/1539634/19679 . I was surprised by this myself. – Brad Larson Dec 06 '11 at 05:08
  • Fix your leak and it should work. You never release your first CGPath, so the compiler may not actually be creating your second to nth paths. I would try releasing and setting path to nil at the end of you loop and the watching to see that new memory locations are actually being loaded into your objects in paths. – Chip Coons Dec 23 '11 at 15:41

1 Answers1

1

The answer to this was much simpler than memory leaks, although the memory leaks would undoubtedly have led to problems down the road. My code simply wouldn't run because I accidentally placed a semicolon at the end of a for line, so the for loop didn't even run.

Chiubaka
  • 801
  • 2
  • 11
  • 27