views:

27

answers:

1

Is anyone else out there using the UACellBackgroundView code to do cell gradients. It works like a champ and I want to continue using it, but it is leaking like a sieve.

I think instruments says that CGPathCreateMutable() is creating a mutable copy but not releasing. This is a little deeper than my memory management skills.

Here is the code I am using: Header:

#import <Foundation/Foundation.h>

#import <UIKit/UIKit.h>

typedef enum {
    UACellBackgroundViewPositionSingle = 0,
    UACellBackgroundViewPositionTop,
    UACellBackgroundViewPositionBottom,
    UACellBackgroundViewPositionMiddle
} UACellBackgroundViewPosition;

@interface UACellBackgroundView : UIView {
    UACellBackgroundViewPosition position;
}

@property(nonatomic) UACellBackgroundViewPosition position;

@end

Class file:

//
// UACellBackgroundView.m
// Ambiance
//
// Created by Matt Coneybeare on 1/31/10.
// Copyright 2010 Urban Apps LLC. All rights reserved.
//

#define TABLE_CELL_BACKGROUND { 1, 1, 1, 1, 0.866, 0.866, 0.866, 1} // #FFFFFF and #DDDDDD
#define kDefaultMargin 10

#import "UACellBackgroundView.h"

static void addRoundedRectToPath(CGContextRef context, CGRect rect, float ovalWidth,float ovalHeight);

@implementation UACellBackgroundView

@synthesize position;

- (BOOL) isOpaque {
    return NO;
}

-(void)drawRect:(CGRect)aRect {
    // Drawing code

    int lineWidth = 1;

    CGRect rect = [self bounds];
    rect.size.width -= lineWidth;
    rect.size.height -= lineWidth;
    rect.origin.x += lineWidth / 2.0;
    rect.origin.y += lineWidth / 2.0;

    CGFloat minx = CGRectGetMinX(rect), midx = CGRectGetMidX(rect), maxx = CGRectGetMaxX(rect);
    CGFloat miny = CGRectGetMinY(rect), midy = CGRectGetMidY(rect), maxy = CGRectGetMaxY(rect);
    maxy += 1;

    CGFloat locations[2] = { 0.0, 1.0 };

    CGContextRef c = UIGraphicsGetCurrentContext();
    CGColorSpaceRef myColorspace = CGColorSpaceCreateDeviceRGB();
    CGGradientRef myGradient = nil;
    CGFloat components[8] = TABLE_CELL_BACKGROUND;
    //CGContextSetStrokeColorWithColor(c, [[UAColor tableCellBorderColor] CGColor]);
    CGContextSetStrokeColorWithColor(c, [[UIColor grayColor] CGColor]);
    CGContextSetLineWidth(c, lineWidth);
    CGContextSetAllowsAntialiasing(c, YES);
    CGContextSetShouldAntialias(c, YES);

    if (position == UACellBackgroundViewPositionTop) {

        CGMutablePathRef path = CGPathCreateMutable();
        CGPathMoveToPoint(path, NULL, minx, maxy);
        CGPathAddArcToPoint(path, NULL, minx, miny, midx, miny, kDefaultMargin);
        CGPathAddArcToPoint(path, NULL, maxx, miny, maxx, maxy, kDefaultMargin);
        CGPathAddLineToPoint(path, NULL, maxx, maxy);
        CGPathAddLineToPoint(path, NULL, minx, maxy);
        CGPathCloseSubpath(path);

  // Fill and stroke the path
  CGContextSaveGState(c);
  CGContextAddPath(c, path);
  CGContextClip(c);

  myGradient = CGGradientCreateWithColorComponents(myColorspace, components, locations, 2);
  CGContextDrawLinearGradient(c, myGradient, CGPointMake(minx,miny), CGPointMake(minx,maxy), 0);

  CGContextAddPath(c, path);
  CGContextStrokePath(c);
  CGContextRestoreGState(c);

    } else if (position == UACellBackgroundViewPositionBottom) {
  maxy -= 1;

  CGMutablePathRef path = CGPathCreateMutable();
        CGPathMoveToPoint(path, NULL, minx, miny);
        CGPathAddArcToPoint(path, NULL, minx, maxy, midx, maxy, kDefaultMargin);
        CGPathAddArcToPoint(path, NULL, maxx, maxy, maxx, miny, kDefaultMargin);
        CGPathAddLineToPoint(path, NULL, maxx, miny);
        CGPathAddLineToPoint(path, NULL, minx, miny);
  CGPathCloseSubpath(path);

  // Fill and stroke the path
  CGContextSaveGState(c);
  CGContextAddPath(c, path);
  CGContextClip(c);

  myGradient = CGGradientCreateWithColorComponents(myColorspace, components, locations, 2);
  CGContextDrawLinearGradient(c, myGradient, CGPointMake(minx,miny), CGPointMake(minx,maxy), 0);

  CGContextAddPath(c, path);
  CGContextStrokePath(c);
  CGContextRestoreGState(c);


    } else if (position == UACellBackgroundViewPositionMiddle) {

  CGMutablePathRef path = CGPathCreateMutable();
  CGPathMoveToPoint(path, NULL, minx, miny);
  CGPathAddLineToPoint(path, NULL, maxx, miny);
  CGPathAddLineToPoint(path, NULL, maxx, maxy);
  CGPathAddLineToPoint(path, NULL, minx, maxy);
  CGPathAddLineToPoint(path, NULL, minx, miny);
  CGPathCloseSubpath(path);

  // Fill and stroke the path
  CGContextSaveGState(c);
  CGContextAddPath(c, path);
  CGContextClip(c);

  myGradient = CGGradientCreateWithColorComponents(myColorspace, components, locations, 2);
  CGContextDrawLinearGradient(c, myGradient, CGPointMake(minx,miny), CGPointMake(minx,maxy), 0);

  CGContextAddPath(c, path);
  CGContextStrokePath(c);
  CGContextRestoreGState(c);

    } else if (position == UACellBackgroundViewPositionSingle) {
  maxy -= 1;

  CGMutablePathRef path = CGPathCreateMutable();
        CGPathMoveToPoint(path, NULL, minx, midy);
        CGPathAddArcToPoint(path, NULL, minx, miny, midx, miny, kDefaultMargin);
        CGPathAddArcToPoint(path, NULL, maxx, miny, maxx, midy, kDefaultMargin);
        CGPathAddArcToPoint(path, NULL, maxx, maxy, midx, maxy, kDefaultMargin);
        CGPathAddArcToPoint(path, NULL, minx, maxy, minx, midy, kDefaultMargin);
  CGPathCloseSubpath(path);

  // Fill and stroke the path
  CGContextSaveGState(c);
  CGContextAddPath(c, path);
  CGContextClip(c);

  myGradient = CGGradientCreateWithColorComponents(myColorspace, components, locations, 2);
  CGContextDrawLinearGradient(c, myGradient, CGPointMake(minx,miny), CGPointMake(minx,maxy), 0);

  CGContextAddPath(c, path);
  CGContextStrokePath(c);
  CGContextRestoreGState(c);
    }

    CGColorSpaceRelease(myColorspace);
    CGGradientRelease(myGradient);
    return;
}

- (void)dealloc {
    [super dealloc];
}

- (void)setPosition:(UACellBackgroundViewPosition)newPosition {
    if (position != newPosition) {
        position = newPosition;
        [self setNeedsDisplay];
    }
}

@end

static void addRoundedRectToPath(CGContextRef context, CGRect rect, float ovalWidth,float ovalHeight) {
    float fw, fh;

    if (ovalWidth == 0 || ovalHeight == 0) {// 1
        CGContextAddRect(context, rect);
        return;
    }

    CGContextSaveGState(context);// 2

    CGContextTranslateCTM (context, CGRectGetMinX(rect),// 3
         CGRectGetMinY(rect));
    CGContextScaleCTM (context, ovalWidth, ovalHeight);// 4
    fw = CGRectGetWidth (rect) / ovalWidth;// 5
    fh = CGRectGetHeight (rect) / ovalHeight;// 6

    CGContextMoveToPoint(context, fw, fh/2); // 7
    CGContextAddArcToPoint(context, fw, fh, fw/2, fh, 1);// 8
    CGContextAddArcToPoint(context, 0, fh, 0, fh/2, 1);// 9
    CGContextAddArcToPoint(context, 0, 0, fw/2, 0, 1);// 10
    CGContextAddArcToPoint(context, fw, 0, fw, fh/2, 1); // 11
    CGContextClosePath(context);// 12

    CGContextRestoreGState(context);// 13
}
A: 

You have 4 invocations of CGGradientCreateWithColorComponents and only 1 invocation of CGGradientRelease. You should release each gradient before creating a new one, to have the same number of invocations.

Laurent Etiemble