0

I got a interesting riddle here. My cocos2d project uses a UIView to display nicer popups than the regular alert view. To be more flexible in the size of the popup, I draw the background in the drawRect method.

But first the hierarchy how I implement cocos2d and UIKit: Hierarchy

Every UIKit element is added to the RootViewController. Every CCNode to the EAGLView. (If someone has a better solution to mix those world, don't wait to tell me!) Unfortunately is every UIKit view in front of cocos nodes.

Everything works fine when I add the first popup to the RootViewController. But if I remove the first popup and add a new one to the RootViewController occurs a bad access. It crashes only in combination with cocos2d.

I use the code from Ray Wenderlichs CoreGraphics 101 tutorial. The crash

context and strokeColor are not nil. Another important infos: I use ARC and am supporting iOS 4.2 and above.

The complete code can be found at raywenderlich.com or below

void drawLinearGradient(CGContextRef context, CGRect rect, CGColorRef startColor, CGColorRef endColor)
{
    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
    CGFloat locations[] = { 0.0, 1.0 };

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

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

    CGPoint startPoint = CGPointMake(CGRectGetMidX(rect), CGRectGetMinY(rect));
    CGPoint endPoint = CGPointMake(CGRectGetMidX(rect), CGRectGetMaxY(rect));

    CGContextSaveGState(context);
    CGContextAddRect(context, rect);
    CGContextClip(context);
    CGContextDrawLinearGradient(context, gradient, startPoint, endPoint, 0);
    CGContextRestoreGState(context);

    CGGradientRelease(gradient);
    CGColorSpaceRelease(colorSpace);
}

CGRect rectFor1PxStroke(CGRect rect)
{
    return CGRectMake(rect.origin.x + 0.5, rect.origin.y + 0.5, rect.size.width - 1, rect.size.height -1);
}

- (void)drawRect:(CGRect)rect
{
    CGContextRef context = UIGraphicsGetCurrentContext();
    CGRect frame = CGRectInset(self.bounds, 2, 2);

    CGContextSetShadowWithColor(context, CGSizeMake(0, 0), 3.0, shadowColor);

    CGRect strokeRect = CGRectInset(frame, -2.0, -2.0);
    CGContextSetStrokeColorWithColor(context, strokeColor);
    CGContextSetLineWidth(context, 2.0);
    CGContextStrokeRect(context, rectFor1PxStroke(strokeRect));
    drawLinearGradient(context, frame, gradient1, gradient2);
}
zeiteisen
  • 7,078
  • 5
  • 50
  • 68
  • This answer solves this issue: http://stackoverflow.com/questions/9963530/app-crashes-when-using-bridge-for-coregraphics-gradient-on-arc – zeiteisen Apr 12 '12 at 08:05
  • zeiteisen ......... check out this forum http://www.cocos2d-iphone.org/forum/topic/6889 there a wrapper to load the UIKit views on top of( as you want the hierarchy of the views) EAGLView. – Ankur Apr 12 '12 at 20:40

2 Answers2

2

ARC releases the CGColorRef named strokeColor. One fix is to replace it with an CGFloat array and use CGContextSetStrokeColor instead CGContextSetStrokeColorWithColor

This answer solves this issue: App crashes when using __bridge for CoreGraphics gradient on ARC

Community
  • 1
  • 1
zeiteisen
  • 7,078
  • 5
  • 50
  • 68
0

I agree with zeiteisen ,ARC releases CGColorRef and the easiest way to solve this by

  • replacing CGContextSetStrokeColorWithColor with CGContextSetStrokeColor(context, components)
  • Change UIColor of strokeColor to 'RGB CGFloat components array' as following:

    static CGFloat red, green, blue, alpha;
    
    - (void)getRGBComponents:(CGFloat [4])components forColor:(UIColor *)color {
    
        [color getRed:&red green:&green blue:&blue alpha:&alpha];//To fetch CGFloat RGB components
    
        for (int component = 0; component < 4; component++) {      
            switch (component) {
                case 0:
                    components[component] = red;
                    break;
                case 1:
                    components[component] = green;
                    break;
                case 2:
                    components[component] = blue;
                    break;
                case 3:
                    components[component] = alpha;
                    break; 
               default:
                   break;
        }
    }
    

    }

Use this method like this:

CGFloat components[4];
UIColor *strokeColor=[UIColor greyColor];//My color 
[self getRGBComponents:components forColor:strokeColor];//'components' will be substituted in CGContextSetStrokeColor
NSLog(@"%f %f %f %f", components[0], components[1], components[2],components[3]);
Alphonse R. Dsouza
  • 2,011
  • 1
  • 14
  • 11