tags:

views:

241

answers:

1

My goal is to make a program that will draw points whenever the screen is touched. This is what I have so far:

The header file:

#import <UIKit/UIKit.h>


@interface ElSimView : UIView 
{
  CGPoint firstTouch;
  CGPoint lastTouch;
  UIColor *pointColor;
  CGRect *points;
  int npoints;
}

@property CGPoint firstTouch;
@property CGPoint lastTouch;
@property (nonatomic, retain) UIColor *pointColor;
@property CGRect *points;
@property int npoints;

@end

The implementation file:

//@synths etc.

- (id)initWithFrame:(CGRect)frame 
{
    return self;
}


- (id)initWithCoder:(NSCoder *)coder
{
  if(self = [super initWithCoder:coder])
  {
    self.npoints = 0;
  }
  return self;
}

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
  UITouch *touch = [touches anyObject];
  firstTouch = [touch locationInView:self];
  lastTouch = [touch locationInView:self];
}

- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
  UITouch *touch = [touches anyObject];
  lastTouch = [touch locationInView:self];  
  points = (CGRect *)malloc(sizeof(CGRect) * ++npoints);
  points[npoints-1] = CGRectMake(lastTouch.x-15, lastTouch.y-15,30,30);
  [self setNeedsDisplay];
}

- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
  UITouch *touch = [touches anyObject];
  lastTouch = [touch locationInView:self];  
  [self setNeedsDisplay];
}

- (void)drawRect:(CGRect)rect 
{
  CGContextRef context = UIGraphicsGetCurrentContext();

  CGContextSetLineWidth(context, 2.0);
  CGContextSetStrokeColorWithColor(context, [UIColor blackColor].CGColor);
  CGContextSetFillColorWithColor(context, pointColor.CGColor);

  for(int i=0; i<npoints; i++)
    CGContextAddEllipseInRect(context, points[i]);
  CGContextDrawPath(context, kCGPathFillStroke);
}


- (void)dealloc {
    free(points);
    [super dealloc];
}


@end

When I load this and click some points, it draws the first points normally, then then next points are drawn along with random ellipses (not even circles).

Also I have another question: When is exactly drawRect executed?

A: 

In -touchesEnded:withEvent:, you have the following code:

points = (CGRect *)malloc(sizeof(CGRect) * ++npoints);
points[npoints-1] = CGRectMake(lastTouch.x-15, lastTouch.y-15,30,30);

You are re-allocating an array for points, but not copying over any of your previous points. This was causing you to use random uninitialized memory values instead of your saved CGRects. Instead, try something like the following:

CGRect *newPoints = (CGRect *)malloc(sizeof(CGRect) * ++npoints);
for (unsigned int currentPoint = 0; currentPoint < (npoints - 1); currentPoint++)
{
    newPoints[currentPoint] = points[currentPoint];
}
free(points);
points = newPoints;

points[npoints-1] = CGRectMake(lastTouch.x-15, lastTouch.y-15,30,30);

You were also leaking the points array before by not freeing it before allocating a new array for its contents.

As far as when -drawRect: is called, it is triggered when the iPhone OS display system needs to recache the content of a UIView. As Daniel stated, this typically happens once on initial display and whenever you manually call -setNeedsDisplay on the UIView.

Brad Larson