# Another solution to Gold Challenge

#1

Following is my solution to the Gold challenge:

BEWARE: My program is only capable of drawing circles. I removed the “line-drawing” code for the sake of simplicity.

First of all, I created a BNRCircle class. Here’s `BNRCircle.h`:

``````#import <UIKit/UIKit.h>

@interface BNRCircle : NSObject

@property (nonatomic) CGPoint startingPoint;
@property (nonatomic) CGPoint endPoint;

@end
``````

And here’s `BNRCircle.m`:

``````#import "BNRCircle.h"

@implementation BNRCircle

@synthesize center = _center;

- (CGPoint)center
{
CGFloat x = (self.startingPoint.x + self.endPoint.x) / 2;
CGFloat y = (self.startingPoint.y + self.endPoint.y) / 2;
return CGPointMake(x, y);
}

{
CGFloat deltaX = self.endPoint.x - self.startingPoint.x;
CGFloat deltaY = self.endPoint.y - self.startingPoint.y;
CGFloat distance = sqrt(deltaX * deltaX + deltaY * deltaY);
return (distance / 2) / sqrt(2);
}

@end
``````

I add four properties to BNRCircle: `startingPoint`, `endPoint`, `center` and `radius`. `startingPoint` and `endPoint` are defined by the location of the user’s touches on the screen. `center` and `radius` are calculated on demand whenever a caller needs them (later on, BNRDrawView will use those two values to draw circles).

The rest of the solution is contained within the BNRDrawView class. `BNRDrawView.h` remains quite simple:

``````#import <UIKit/UIKit.h>

@interface BNRDrawView : UIView

@end
``````

While `BNRDrawView.m` contains most of the logic:

``````#import "BNRDrawView.h"
#import "BNRLine.h"
#import "BNRCircle.h"

const int CIRCLE = 0;
const int POINT = 1;
NSString * const kLabelStartingPoint = @"STARTING_POINT";
NSString * const kLabelEndPoint = @"END_POINT";

@interface BNRDrawView ()

@property (nonatomic, strong) NSMutableArray *currentTouches;
@property (nonatomic, strong) NSMutableDictionary *circlesInProgress;
@property (nonatomic, strong) NSMutableArray *finishedCircles;

@end

@implementation BNRDrawView

# pragma mark - View life cycle

- (instancetype)initWithFrame:(CGRect)frame
{
if (self = [super initWithFrame:frame]) {
self.currentTouches = [[NSMutableArray alloc] init];
self.circlesInProgress = [[NSMutableDictionary alloc] init];
self.finishedCircles = [[NSMutableArray alloc] init];

self.backgroundColor = [UIColor grayColor];
self.multipleTouchEnabled = YES;
}
return self;
}

# pragma mark - Touch events

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
// Let's put in a log statement to see the order of events
NSLog(@"%@", NSStringFromSelector(_cmd));

for (UITouch *t in touches) {

NSInteger touchCount = self.currentTouches.count;
if (touchCount % 2) {
// do nothing; another touch is needed to define a circle
} else {
// we have an even number of touches; we can define a circle now
BNRCircle *circle = [[BNRCircle alloc] init];

UITouch *startingTouch = self.currentTouches[touchCount - 2];
NSValue *startingTouchRef = [NSValue valueWithNonretainedObject:startingTouch];
circle.startingPoint = [startingTouch locationInView:self];

UITouch *endTouch = self.currentTouches[touchCount - 1];
NSValue *endTouchRef = [NSValue valueWithNonretainedObject:endTouch];
circle.endPoint = [endTouch locationInView:self];

self.circlesInProgress[startingTouchRef] = @[circle, kLabelStartingPoint];
self.circlesInProgress[endTouchRef] = @[circle, kLabelEndPoint];
}

[self setNeedsDisplay];
}
}

- (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
// Let's put in a log statement to see the order of events
NSLog(@"%@", NSStringFromSelector(_cmd));

for (UITouch *t in touches) {
NSValue *tRef = [NSValue valueWithNonretainedObject:t];
BNRCircle *circle = self.circlesInProgress[tRef][CIRCLE];
NSString *label = self.circlesInProgress[tRef][POINT];

if ([label isEqualToString:kLabelStartingPoint]) {
circle.startingPoint = [t locationInView:self];
} else {
circle.endPoint = [t locationInView:self];
}
}

[self setNeedsDisplay];
}

- (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
// Let's put in a log statement to see the order of events
NSLog(@"%@", NSStringFromSelector(_cmd));

for (UITouch *t in touches) {
NSValue *tRef = [NSValue valueWithNonretainedObject:t];

[self.currentTouches removeObject:t];
NSInteger touchCount = self.currentTouches.count;

if (touchCount % 2 == 0) {
// there's an even number of touches left: one circle has been finalized
BNRCircle *circle = self.circlesInProgress[tRef][CIRCLE];
if (circle) {
}
}

[self.circlesInProgress removeObjectForKey:tRef];
[self setNeedsDisplay];
}
}

# pragma mark - Circle drawing

- (void)strokeCircle:(BNRCircle *)circle
{
UIBezierPath *bp = [UIBezierPath bezierPath];
bp.lineWidth = 10;

startAngle:0.0
endAngle:M_PI * 2.0
clockwise:YES];
[bp stroke];
}

- (void)drawRect:(CGRect)rect
{
// Draw finished circles in black
[[UIColor blackColor] set];
for (BNRCircle *circle in self.finishedCircles) {
[self strokeCircle:circle];
}

// Draw circles in progress in red
[[UIColor redColor] set];
for (NSValue *tRef in self.circlesInProgress) {
BNRCircle *circle = self.circlesInProgress[tRef][CIRCLE];
[self strokeCircle:circle];
}
}

@end
``````

Current touches on screen are tracked via the `currentTouches` array.

Circles in progress are tracked via the `circlesInProgress` dictionary: `circlesInProgress` is a dictionary that maps the NSValue of a UITouch to an array composed of two elements: the circle partially defined by that touch, and a string constant indicating which of the two bounding points is the touch related to.