9

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

dimme
  • 4,393
  • 4
  • 31
  • 51

3 Answers3

9

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/

Justyn
  • 1,442
  • 12
  • 27
Cristi
  • 1,488
  • 1
  • 14
  • 14
  • 1
    There's just a little typo in the answer: the right function to call is GradientRefWithColors() and not CreateGradientRefWithColors(). That said THIS should be the right/accepted answer, 'cause it the only one that actually solve the problem... – il Malvagio Dottor Prosciutto Sep 25 '12 at 07:43
7

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.

Anya Shenanigans
  • 91,618
  • 3
  • 107
  • 122
  • It gives: `Incompatible types casting 'CGColorRef [2]' to 'void **' with a __bridge cast`. However, I just found this: https://github.com/LordLobo/LLRoundSwitch I'm going to try it out. – dimme Dec 10 '11 at 15:52
  • 1
    It didn't help. It suffers from the same bug. – dimme Dec 10 '11 at 15:59
  • I use this solution but still get me Incompatible types casting 'CGColorRef' *'aka'struct CGColor to 'void' **' with a__bridge cast – wod Dec 24 '12 at 13:37
  • Apologies, I left the incorrect answer at the bottom of the main answer, which exhibits the problem you mentioned. Please use the code at the start of the answer, rather than the broken remainder code. – Anya Shenanigans Dec 24 '12 at 14:23
5

colorsArray is released using the method CFRelease. ARC doesn't allow the use of retain and release, so why don't you try commenting the line CFRelease(colorsArray) and see if that prevents the error?

Edit--

This answer was accepted as it supplied a valid fix to the OP's issue, by disabling ARC.

If you do not want to use this method, please see @petesh's answer.

max_
  • 24,076
  • 39
  • 122
  • 211
  • 1
    Can you upload your arc refactored code? Also, it may just be better to turn off arc for the individual files. I just tested it out and it works perfectly - http://cl.ly/3p0O0f3m1B1d0K1h0L3S – max_ Dec 10 '11 at 15:31
  • 4
    +1 because I solved it by turning off ARC for this individual file. Guide: http://stackoverflow.com/questions/6646052/how-can-i-disable-arc-for-a-single-file-in-a-project – dimme Dec 10 '11 at 16:22
  • Exact same problem here, turning off ARC with the compiler flag fixed it for me. – TheJerkMan24 Apr 24 '12 at 16:50