views:

40

answers:

3

I have a little UIView object, CircleColorView.m, that simply creates a view with a colored circle in it. I then use that view as the background to a bunch of buttons (all different colors).

My problem happens when the drawRect: method gets called. I crash, but only sometimes, when I reference the object color which is a UIColor.

I am very confused. Here is my UIView:

ColorCircleView.h

#import <UIKit/UIKit.h>
#import "Constants.h"

@interface CircleColorView : UIView {

    UIColor *color;

}

@property (nonatomic, retain) UIColor *color;

- (id)initWithFrame:(CGRect)frame andColor:(UIColor *)circleColor;

@end

And here is ColorCircleView.m

#import "CircleColorView.h"


@implementation CircleColorView
@synthesize color;

- (id)initWithFrame:(CGRect)frame andColor:(UIColor *)circleColor {
    if ((self = [super initWithFrame:frame])) {
        color = [UIColor colorWithCGColor:[circleColor CGColor]];

                // have also tried
                // color = circleColor;


    }

    return self;
}


- (void) drawRect: (CGRect) aRect
{
    CGFloat iconSize = self.frame.size.width;

        // Create a new path
    CGContextRef context = UIGraphicsGetCurrentContext();
    CGMutablePathRef path = CGPathCreateMutable();

        // Set up fill for circle
    const CGFloat* fill = CGColorGetComponents(color.CGColor);
    CGContextSetFillColor(context, fill);

        // Add circle to path
    CGRect limits = CGRectMake(8.0f, 8.0f, iconSize - 16.0f, iconSize - 16.0f);
    CGPathAddEllipseInRect(path, NULL, limits);
    CGContextAddPath(context, path);

    CGContextFillEllipseInRect(context, limits);
    CGContextFillPath(context);
    CFRelease(path);
}




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


@end

Here is the code that I use to create and add the CircleColorView to a button image. It is inside a loop that is going through an array of strings with color values separated by a ;

NSArray *values = [[NSArray alloc] initWithArray:[[[colorListArray objectAtIndex:i] objectAtIndex:1] componentsSeparatedByString:@";"]];
    float red = [[values objectAtIndex:0] floatValue];
    float green = [[values objectAtIndex:1] floatValue];
    float blue = [[values objectAtIndex:2] floatValue];

    UIColor *color = [[UIColor alloc]
                      initWithRed: (float) (red/255.0f)
                      green: (float) (green/255.0f)
                      blue:  (float) (blue/255.0f)
                      alpha: 1.0];
    UIButton *newColorButton = [UIButton buttonWithType:0];

        //Create Colored Circle
    CircleColorView *circle = [[CircleColorView alloc] initWithFrame:CGRectMake(0, 0, 75, 75) andColor:color ];
    circle.backgroundColor = [UIColor clearColor];

       //Set Button Attributes
    [newColorButton setTitle:[[colorListArray objectAtIndex:i] objectAtIndex:1] forState:UIControlStateDisabled];
    [newColorButton setFrame:CGRectMake(600+(i*82), 12, 75, 75)]; //set location of each button in scrollview
    [newColorButton addTarget:self action:@selector(changeColor:) forControlEvents:UIControlEventTouchDown];
    [newColorButton setTag:tagNum];
    [barContentView addSubview:newColorButton];
    [circle release];
    [color release];
    [values release];

I've logged it to see what happens. Looks like it runs CircleColorView's initWithFrame:andColor: just fine. Then when the drawRect: is called, it will crash the first time the property 'color' is referenced. Even if it is just asking it for a discription like [color description].

Any ideas. Am I creating this UIColor *color wrong? Or retaining it wrong? Here is another strange thing. This code runs just fine for a while. Then when I quit and restart the app it will crash. To get it to work again I have deleted the build file and the app folder in the iPhone simulator. That will allow it to work again. The only other thing that will consistantly get it to work is by just changing the UIColor *color @property to assign or vice versa. That will allow me to rebuild the app and run it with no problems once or twice again. Then it crashes. Oh, and it does the same thing on the device. Any ideas???

Thanks in advance,

Mark

+1  A: 
color = [UIColor colorWithCGColor:[circleColor CGColor]];
[color retain];

By not having the [color retain] code it is autoreleased and that will randomly happen.

You wouldn't need the [color retain] if your did something like color = [[UIColor alloc] initWithCGColor:[circleColor CGColor]]; or something similar that had init in the creation.

jamone
You also wouldn't need the retain is you assigned to self.color instead of color (because then the synthesized property takes care of the retain), but I remember seeing an Apple recommendation not to use self.property in the initializer (I don't quite understand why though).
John N
Yeah, I remember seeing that recommendation not to use self.property also. I remember I understood why once upon a time, but now it escapes me.
jamone
Yes, thank you. It did fix the problem. I was thinking that because of the @property, it would keep that attribute after assignment. Thanks.
Mark A.
If this fixed it make sure you choose an answer.
jamone
+1  A: 

Because you are assigning directly to "color", and not using the "." accessor syntax, the setter method is not getting called, so the value you're assigning isn't retained.

You need to either explicitly retain color, or use the . syntax:

self.color = [UIColor colorWithCGColor:[circleColor CGColor]];
David Gelhar
+1  A: 

This line declares the color property, which will retain the color when assigned.

@property (nonatomic, retain) UIColor *color;

This line bypasses the property setter and assigns an autoreleased object directly to the member.

color = [UIColor colorWith...

You can fix it with either:

self.color = [UIColor colorWith...

or

[color retain];

or

color = [[UIColor alloc] initWith...
drawnonward