Puzzled


#1

Hi everyone,

 I'm totally lost as to why one method works, and another breaks the program.  It's not really important, but I'd really like to know what's happening.  When I use [[UIColor greenColor] setStroke], the program works fine.  When I change that to CGRectSetRGBStrokeColor (ctx, 0.6, 0.6, 0.6, 1), I get an exc_bad_access error.  I've narrowed it down to the following if statement:

     
    if(deviceDidShake == NO)
    {
        
        
        if(currentRadius >= 240)
        {
        [self setCircleColor:[UIColor orangeColor]];
        [[self circleColor] setStroke];
        NSLog(@"The colour is orange.");
        }
        
        else if(currentRadius >= 140)
        {
        [self setCircleColor:[UIColor greenColor]];
        [[self circleColor] setStroke];
        NSLog(@"The colour is green.");
        }
        
        else if(currentRadius >= 0)
        {
            [self setCircleColor:[UIColor blueColor]];
            [[self circleColor] setStroke];
           NSLog(@"The colour is blue.");
        }
    }

Here’s the whole code:


//
//  HypnosisView.m
//  Hypnosister
//
//  Created by refcio on 2013-07-14.
//  Copyright (c) 2013 refcio. All rights reserved.
//

#import "HypnosisView.h"

@implementation HypnosisView

@synthesize circleColor;

- (id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self)
    {
    // Initialization code
    // All HypnosisViews start with a clear background colour.
    [self setBackgroundColor:[UIColor clearColor]];
    // Set default circle colour.
    [self setCircleColor:[UIColor lightGrayColor]];
    }
    return self;
}

/*
// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
- (void)drawRect:(CGRect)rect
{
    // Drawing code
}
*/

- (void)drawRect:(CGRect)dirtyRect
{
    CGContextRef ctx = UIGraphicsGetCurrentContext();
    CGRect bounds = [self bounds];
    
    // Figure out the centre of the bounds rectangle.
    CGPoint center;
    center.x = bounds.origin.x + bounds.size.width / 2.0;
    center.y = bounds.origin.y + bounds.size.height / 2.0;
    
    // The radius of the circle should be nearly as big as the view.
    //float maxRadius = hypot(bounds.size.width, bounds.size.height) / 4.0;
    float maxRadius = hypot(bounds.size.width, bounds.size.height) / 2.0;
    
    // The thickness of the line should be 10 points wide.
    CGContextSetLineWidth(ctx, 10);
    
    [self setCircleColor:[UIColor lightGrayColor]];
                          
    [[self circleColor] setStroke];
    
    // The colour of the line should be gray (red/green/blue = 0.6, alpha = 1.0);
    //CGContextSetRGBStrokeColor(ctx, 0.6, 0.6, 0.6, 1.0);
    
    //[[UIColor colorWithRed:0.6 green:0.6 blue:0.6 alpha:1.0] setStroke];
    
    //[[UIColor lightGrayColor] setStroke];
    
    // Add a shape to the context - this does not draw the shape.
    //CGContextAddArc(ctx, center.x, center.y, maxRadius, 0.0, M_PI * 2.0, YES);
    
    // Perform a drawing instruction; draw current shape with current state
    //CGContextStrokePath(ctx);
    
    // Draw concentric circles from the outside in.
    for (float currentRadius = maxRadius; currentRadius > 0; currentRadius -= 20)
    {

            if(deviceDidShake == NO)
            {
                if(currentRadius >= 240)
                {
                [self setCircleColor:[UIColor orangeColor]];
                [[self circleColor] setStroke];
                NSLog(@"The colour is orange.");
                }
        
                else if(currentRadius >= 140)
                {
                [self setCircleColor:[UIColor greenColor]];
                [[self circleColor] setStroke];
                NSLog(@"The colour is green.");
                }
        
                else if(currentRadius >= 0)
                {
                [self setCircleColor:[UIColor blueColor]];
                [[self circleColor] setStroke];
                NSLog(@"The colour is blue.");
                }
            }
    
        // Add a path to the context.
        CGContextAddArc(ctx, center.x, center.y, currentRadius, 0.0, M_PI * 2.0, YES);
        
        // Perform drawing instruction; removes path
        CGContextStrokePath(ctx);
        //sleep(5);
        //[NSThread sleepForTimeInterval:0.5f];
        
        
        
        NSLog(@"This is loop #:  %f", currentRadius);

    }
    
    // Create a string.
    NSString *text = @"You are getting sleepy.";
    
    // Get a font to draw it in.
    UIFont *font = [UIFont boldSystemFontOfSize:28];
    
    CGRect textRect;
    
    // How big is this string when drawn in this font?
    textRect.size = [text sizeWithFont:font];
    
    // Let's put that string in the center of the view.
    textRect.origin.x = center.x - textRect.size.width /2.0;
    textRect.origin.y = center.y - textRect.size.height /2.0;
    
    // Set the fill colour of the current context to black.
    [[UIColor blackColor] setFill];
    
    // The shadow will move 4 points to the right and 3 points down from the text.
    CGSize offset = CGSizeMake(4,3);
    
    // The shadow will be dark gray in colour.
    CGColorRef color = [[UIColor darkGrayColor] CGColor];
    
    // Set the shadow of the context with these parameters.
    // All subsequent drawing will be shadowed.
    CGContextSetShadowWithColor(ctx, offset, 2.0, color);
    
    // Draw the string.
    [text drawInRect:textRect withFont:font];
    
    
//    // Begin the path.
////    CGContextBeginPath(ctx2);
//    
    // Set the line width.
    CGContextSetLineWidth(ctx, 2);
    
    // Set the colour.
    CGContextSetRGBStrokeColor(ctx, 0.6, 0.6, 0.6, 1.0);
  
//    [[UIColor greenColor] setStroke];
    
    // Move to the point where the drawing should start.
    CGContextMoveToPoint(ctx, center.x,center.y);

   //Draw a line horizontally.
    CGContextAddLineToPoint(ctx, 50, 0);
    
//    // Draw a line vertically.
//    CGContextAddLineToPoint(ctx, 0, 50);
    
    // Stroke the path.
    CGContextStrokePath(ctx);

    
    
    
//    // Set line width and color
//    CGContextSetLineWidth(ctx, 2);
//    [[UIColor greenColor] setStroke];
//    
//    // Draw vertical line
//    CGContextMoveToPoint(ctx, center.x, center.y + 35);
//    CGContextAddLineToPoint(ctx, center.x, center.y - 35);
//    CGContextStrokePath(ctx);
    
    
}

- (BOOL)canBecomeFirstResponder
{
    return YES;
}

- (void)motionBegan:(UIEventSubtype)motion withEvent:(UIEvent *)event
{
    if (motion == UIEventSubtypeMotionShake)
    {
    NSLog(@"Device started shaking!");
    [self setCircleColor:[UIColor redColor]];
    deviceDidShake = YES;
    }
}

- (void)setCircleColor:(UIColor *)clr
{
    circleColor = clr;
    [self setNeedsDisplay];
}

@end

Thanks! :slight_smile:


#2

Hard to tell what’s happening from your code, because it is not clean.
Try the following code, which uses both methods of setting the stroke color, to see if you get the same error:

struct MyColor
{
    CGFloat red, green, blue, alpha;
};

struct MyColor RandomColor () {
    struct MyColor color = {
        0.01 * arc4random_uniform (100),
        0.01 * arc4random_uniform (100),
        0.01 * arc4random_uniform (100),
        0.01 * arc4random_uniform (100)
    };
    return color;
}

- (void)drawRect:(CGRect)rect
{
    CGContextRef ctx = UIGraphicsGetCurrentContext();
    CGRect bounds = [self bounds];
    
    CGPoint center;
    center.x = bounds.origin.x + bounds.size.width / 2.0;
    center.y = bounds.origin.y + bounds.size.height / 2.0;
    
    CGContextSetLineWidth (ctx, 10);
    struct MyColor color = RandomColor ();
    CGContextSetRGBStrokeColor (ctx, color.red, color.green, color.blue, color.alpha);
    CGContextAddArc (ctx, center.x, center.y, 1 + arc4random_uniform (100), 0.0, M_PI * 2.0, YES);
    CGContextStrokePath (ctx);
    
    color = RandomColor ();
    [[UIColor colorWithRed:color.red green:color.green blue:color.blue alpha:color.alpha] setStroke];
    CGContextAddArc (ctx, 20 + center.x, 20 + center.y, 10 + arc4random_uniform (100), 0.0, M_PI * 2.0, YES);
    CGContextStrokePath (ctx);
}

#3

Thanks for the reply! :slight_smile: Yeah, sorry about the extra segments of code. I tried the code you suggested and it runs fine without any errors. Basically what’s happening is it crashes because of something in these 3 if statements:

if(currentRadius >= 240)
{
[self setCircleColor:[UIColor orangeColor]];
[[self circleColor] setStroke];
NSLog(@“The colour is orange.”);
}

else if(currentRadius >= 140)
{
[self setCircleColor:[UIColor greenColor]];
[[self circleColor] setStroke];
NSLog(@“The colour is green.”);
}

else if(currentRadius >= 0)
{
[self setCircleColor:[UIColor blueColor]];
[[self circleColor] setStroke];
NSLog(@“The colour is blue.”);
}


#4

[quote]

[code]

  • (void)setCircleColor:(UIColor *)clr
    {
    circleColor = clr;
    [self setNeedsDisplay];
    }

@end
[/code][/quote]
Try commenting out [self setNeedsDisplay]; to see if it still crashes.


#5

Tried that, still gives the same error:

Thread 1: EXC_BAD_ACCESS (code=2, address=0x5a925)

0x52e17: movl %esi, (%esp)

Not sure if that helps you. Sorry I don’t want to waste your time, just this is one of those things that bugs me because I don’t understand it. lol I really appreciate your help!


#6

Ok, so I’ve done a whack of debugging and finally narrowed down the error to this bit of code:

// The shadow will move 4 points to the right and 3 points down from the text.
CGSize offset = CGSizeMake(4,3);

// The shadow will be dark gray in colour.
CGColorRef color = [[UIColor darkGrayColor] CGColor];

// Set the shadow of the context with these parameters.
// All subsequent drawing will be shadowed.
CGContextSetShadowWithColor(ctx, offset, 2.0, color);

When I uncomment this I get a bad_exc_access error. When I take it out, the program runs fine. Any ideas? I think it’s one of those cases where something else is happening somewhere else in the code, possibly to release an object too early, but I have no idea which one or why. Any help would be appreciated. Thanks!