user3069232 user3069232 - 1 year ago 148
Objective-C Question

Two routines one in objective C, the other in Swift same code essentially different results

iOS 10.2 Swift 3.0

Trying to convert this code in objective C to Swift 3.0 and don't know the core graphics library too well.

@interface SPGripViewBorderView : UIView
@end

@implementation SPGripViewBorderView

- (id)initWithFrame:(CGRect)frame {
if ((self = [super initWithFrame:frame])) {
// Clear background to ensure the content view shows through.
self.backgroundColor = [UIColor clearColor];
}
return self;
}

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

// (1) Draw the bounding box.
CGContextSetLineWidth(context, 1.0);
CGContextSetStrokeColorWithColor(context, [UIColor blueColor].CGColor);
CGContextAddRect(context, CGRectInset(self.bounds, kSPUserResizableViewInteractiveBorderSize/2, kSPUserResizableViewInteractiveBorderSize/2));
CGContextStrokePath(context);

// (2) Calculate the bounding boxes for each of the anchor points.
CGRect upperLeft = CGRectMake(0.0, 0.0, kSPUserResizableViewInteractiveBorderSize, kSPUserResizableViewInteractiveBorderSize);
CGRect upperRight = CGRectMake(self.bounds.size.width - kSPUserResizableViewInteractiveBorderSize, 0.0, kSPUserResizableViewInteractiveBorderSize, kSPUserResizableViewInteractiveBorderSize);
CGRect lowerRight = CGRectMake(self.bounds.size.width - kSPUserResizableViewInteractiveBorderSize, self.bounds.size.height - kSPUserResizableViewInteractiveBorderSize, kSPUserResizableViewInteractiveBorderSize, kSPUserResizableViewInteractiveBorderSize);
CGRect lowerLeft = CGRectMake(0.0, self.bounds.size.height - kSPUserResizableViewInteractiveBorderSize, kSPUserResizableViewInteractiveBorderSize, kSPUserResizableViewInteractiveBorderSize);
CGRect upperMiddle = CGRectMake((self.bounds.size.width - kSPUserResizableViewInteractiveBorderSize)/2, 0.0, kSPUserResizableViewInteractiveBorderSize, kSPUserResizableViewInteractiveBorderSize);
CGRect lowerMiddle = CGRectMake((self.bounds.size.width - kSPUserResizableViewInteractiveBorderSize)/2, self.bounds.size.height - kSPUserResizableViewInteractiveBorderSize, kSPUserResizableViewInteractiveBorderSize, kSPUserResizableViewInteractiveBorderSize);
CGRect middleLeft = CGRectMake(0.0, (self.bounds.size.height - kSPUserResizableViewInteractiveBorderSize)/2, kSPUserResizableViewInteractiveBorderSize, kSPUserResizableViewInteractiveBorderSize);
CGRect middleRight = CGRectMake(self.bounds.size.width - kSPUserResizableViewInteractiveBorderSize, (self.bounds.size.height - kSPUserResizableViewInteractiveBorderSize)/2, kSPUserResizableViewInteractiveBorderSize, kSPUserResizableViewInteractiveBorderSize);

// (3) Create the gradient to paint the anchor points.
CGFloat colors [] = {
0.4, 0.8, 1.0, 1.0,
0.0, 0.0, 1.0, 1.0
};
CGColorSpaceRef baseSpace = CGColorSpaceCreateDeviceRGB();
CGGradientRef gradient = CGGradientCreateWithColorComponents(baseSpace, colors, NULL, 2);
CGColorSpaceRelease(baseSpace), baseSpace = NULL;

// (4) Set up the stroke for drawing the border of each of the anchor points.
CGContextSetLineWidth(context, 1);
CGContextSetShadow(context, CGSizeMake(0.5, 0.5), 1);
CGContextSetStrokeColorWithColor(context, [UIColor whiteColor].CGColor);

// (5) Fill each anchor point using the gradient, then stroke the border.
CGRect allPoints[8] = { upperLeft, upperRight, lowerRight, lowerLeft, upperMiddle, lowerMiddle, middleLeft, middleRight };
for (NSInteger i = 0; i < 8; i++) {
CGRect currPoint = allPoints[i];
CGContextSaveGState(context);
CGContextAddEllipseInRect(context, currPoint);
CGContextClip(context);
CGPoint startPoint = CGPointMake(CGRectGetMidX(currPoint), CGRectGetMinY(currPoint));
CGPoint endPoint = CGPointMake(CGRectGetMidX(currPoint), CGRectGetMaxY(currPoint));
CGContextDrawLinearGradient(context, gradient, startPoint, endPoint, 0);
CGContextRestoreGState(context);
CGContextStrokeEllipseInRect(context, CGRectInset(currPoint, 1, 1));
}
CGGradientRelease(gradient), gradient = NULL;
CGContextRestoreGState(context);
}

@end


Which I re-coded as this ...

import UIKit

class GripViewBorderView: UIView {

let kUserResizableViewInteractiveBorderSize:CGFloat = 10.0

required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}

override init(frame: CGRect) {
super.init(frame: frame)
}


override func draw(_ rect:CGRect) {
let context = UIGraphicsGetCurrentContext();
context!.saveGState();

// (1) Draw the bounding box.
context!.setLineWidth(1.0);
context!.setStrokeColor(UIColor.blue.cgColor)
//CGContextAddRect(context!, CGRectInset(self.bounds, (kSPUserResizableViewInteractiveBorderSize / 2.0), (kSPUserResizableViewInteractiveBorderSize / 2.0)));
context!.addRect(self.bounds.insetBy(dx: (kUserResizableViewInteractiveBorderSize / 2.0), dy: (kUserResizableViewInteractiveBorderSize / 2.0)))
context!.strokePath();

// (2) Calculate the bounding boxes for each of the anchor points.
let upperLeft = CGRect(x: 0.0, y: 0.0, width: kUserResizableViewInteractiveBorderSize, height: kUserResizableViewInteractiveBorderSize)
let upperRight = CGRect(x: self.bounds.size.width - kUserResizableViewInteractiveBorderSize, y: 0.0, width: kUserResizableViewInteractiveBorderSize, height: kUserResizableViewInteractiveBorderSize);
let lowerRight = CGRect(x: self.bounds.size.width - kUserResizableViewInteractiveBorderSize, y: self.bounds.size.height - kUserResizableViewInteractiveBorderSize, width: kUserResizableViewInteractiveBorderSize, height: kUserResizableViewInteractiveBorderSize);
let lowerLeft = CGRect(x: 0.0, y: self.bounds.size.height - kUserResizableViewInteractiveBorderSize, width: kUserResizableViewInteractiveBorderSize, height: kUserResizableViewInteractiveBorderSize);
let upperMiddle = CGRect(x: (self.bounds.size.width - kUserResizableViewInteractiveBorderSize)/2, y: 0.0, width: kUserResizableViewInteractiveBorderSize, height: kUserResizableViewInteractiveBorderSize);
let lowerMiddle = CGRect(x: (self.bounds.size.width - kUserResizableViewInteractiveBorderSize)/2, y: self.bounds.size.height - kUserResizableViewInteractiveBorderSize, width: kUserResizableViewInteractiveBorderSize, height: kUserResizableViewInteractiveBorderSize);
let middleLeft = CGRect(x: 0.0, y: (self.bounds.size.height - kUserResizableViewInteractiveBorderSize)/2, width: kUserResizableViewInteractiveBorderSize, height: kUserResizableViewInteractiveBorderSize);
let middleRight = CGRect(x: self.bounds.size.width - kUserResizableViewInteractiveBorderSize, y: (self.bounds.size.height - kUserResizableViewInteractiveBorderSize)/2, width: kUserResizableViewInteractiveBorderSize, height: kUserResizableViewInteractiveBorderSize);

// (3) Create the gradient to paint the anchor points.
let baseSpace = CGColorSpaceCreateDeviceRGB()
//let gradient = CGGradientCreateWithColorComponents(baseSpace, colors, NULL, 2)
let colors = [UIColor.red.cgColor,
UIColor.yellow.cgColor]

let gradient = CGGradient(colorsSpace: baseSpace, colors: colors as CFArray, locations: nil)

// (4) Set up the stroke for drawing the border of each of the anchor points.
context!.setLineWidth(1)
context!.setShadow(offset: CGSize(width: 0.5, height: 0.5), blur: 1)
context!.setStrokeColor(UIColor.white.cgColor)

// (5) Fill each anchor point using the gradient, then stroke the border.
let allPoints:[CGRect] = [ upperLeft, upperRight, lowerRight, lowerLeft, upperMiddle, lowerMiddle, middleLeft, middleRight ];
for i in 0 ... 7 {
let currPoint = allPoints[i]
context!.saveGState()
context!.addEllipse(in: currPoint)
context!.clip()
let startPoint = CGPoint(x: currPoint.midX, y: currPoint.minY);
let endPoint = CGPoint(x: currPoint.midX, y: currPoint.maxY);
context!.drawLinearGradient(gradient!, start: startPoint, end: endPoint, options: .init(rawValue: 0))
context!.saveGState()
context!.strokeEllipse(in: currPoint.insetBy(dx: 1, dy: 1))
}
context!.restoreGState()
}


}


But I missed something cause the OOC is on the left and my new Swift on the right. For reasons I cannot figure I get only a single dot drawn in my version, the OOC version draws 8 dots [correctly].

enter image description here

Answer Source

You have written context!.saveGState() at the end of the for loop in place of CGContextRestoreGState(context). It should, of course, be context!.restoreGState(). Simple typo!

Also, please remove all of the semi-colons, and use guard let context = UIGraphicsGetCurrentContext() else { return } to get rid of all those forced unwrappings!

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download