Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

DCRoundSwitch gives EXC_BAD_ACCESS when using ARC

I'm using DCRoundSwitch for a project where I basically need an UISwitch where I'm able to edit its label contents.

Because I'm using ARC I refactored the DCRoundSwitch code to be ARC-compatible in xcode.

When compiling and running in the simulator it works without any problems.

However, when running on the device it gives me EXC_BAD_ACCESS near line 57 of DCRoundSwitchKnobLayer.m

There is a bug report at GitHub but no solution has been found yet.

Here is the code that gives EXC_BAD_ACCESS:

CGGradientRef CreateGradientRefWithColors(CGColorSpaceRef colorSpace, CGColorRef startColor, CGColorRef endColor)
{
    CGFloat colorStops[2] = {0.0, 1.0};
    CGColorRef colors[] = {startColor, endColor};

    //THIS LINE BREAKS THE PROGRAM
    CFArrayRef colorsArray = CFArrayCreate(NULL, (const void**)colors, sizeof(colors) / sizeof(CGColorRef), &kCFTypeArrayCallBacks); 

    CGGradientRef gradient = CGGradientCreateWithColors(colorSpace, colorsArray, colorStops);
    CFRelease(colorsArray);
    return gradient;
}

Any clues would be appreciated.

EDIT: Here are the local variables from xcode:

enter image description here

like image 621
Dimme Avatar asked Dec 10 '11 15:12

Dimme


2 Answers

I had the same problem and I really wanted to convert the code to ARC. The crash occurs because startColor and endColor are already freed when CreateGradientRefWithColors is called.

Here is my fix:

- (void)drawInContext:(CGContextRef)context
{
    UIColor *startColor = [UIColor colorWithRed:0.0 green:0.0 blue:0.0 alpha:1.0];
    UIColor *endColor = [UIColor colorWithRed:1.0 green:1.0 blue:1.0 alpha:1.0];

    NSArray *colors = [NSArray arrayWithObjects:(__bridge id)startColor.CGColor, (__bridge id) endColor.CGColor, nil];

    CGGradientRef gradient = CGGradientCreateWithColors(colorSpace, (__bridge CFArrayRef) colors, locations);
}

This post helped in finding the solution: http://www.bobmccune.com/2012/02/28/a-funny-thing-happened-on-the-way-to-the-arc/

like image 86
Cristi Avatar answered Sep 29 '22 20:09

Cristi


EDIT

Apologies, the correct fix for this code with ARC is:

CGGradientRef CreateGradientRefWithColors(CGColorSpaceRef colorSpace, CGColorRef startColor, CGColorRef endColor)
{
    CGFloat colorStops[2] = {0.0, 1.0};
    NSArray *colors = [NSArray arrayWithObjects:(id)startColor, (id)endColor, nil];

    CGGradientRef gradient = CGGradientCreateWithColors(colorSpace, (__bridge CFArrayRef)colors, colorStops);

    return gradient;
}

You use a bridge conversion from an NSArray of the colors, rather than going to the extra work of creating the the CFArrayRef. This refactoring is shamelessly stolen from the Discussions on Core Graphics 101. Which is an awesome site of turorials on Objective-C.

The Everything you wanted to know about ARC has a few guides about this. The ARC Q&A also has some good guides on this.

like image 37
Petesh Avatar answered Sep 29 '22 22:09

Petesh