diff --git a/FreehandDrawing-iOS.xcodeproj/project.pbxproj b/FreehandDrawing-iOS.xcodeproj/project.pbxproj index 6692919..efa9bef 100644 --- a/FreehandDrawing-iOS.xcodeproj/project.pbxproj +++ b/FreehandDrawing-iOS.xcodeproj/project.pbxproj @@ -215,9 +215,11 @@ TargetAttributes = { 47919A3D1B0CE08600D7BFE9 = { CreatedOnToolsVersion = 6.1.1; + LastSwiftMigration = 0820; }; 47919A521B0CE08600D7BFE9 = { CreatedOnToolsVersion = 6.1.1; + LastSwiftMigration = 0820; TestTargetID = 47919A3D1B0CE08600D7BFE9; }; }; @@ -403,6 +405,7 @@ INFOPLIST_FILE = "FreehandDrawing-iOS/Info.plist"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 3.0; }; name = Debug; }; @@ -413,6 +416,7 @@ INFOPLIST_FILE = "FreehandDrawing-iOS/Info.plist"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 3.0; }; name = Release; }; @@ -431,6 +435,7 @@ INFOPLIST_FILE = "FreehandDrawing-iOSTests/Info.plist"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 3.0; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/FreehandDrawing-iOS.app/FreehandDrawing-iOS"; }; name = Debug; @@ -446,6 +451,7 @@ INFOPLIST_FILE = "FreehandDrawing-iOSTests/Info.plist"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 3.0; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/FreehandDrawing-iOS.app/FreehandDrawing-iOS"; }; name = Release; diff --git a/FreehandDrawing-iOS/AppDelegate.swift b/FreehandDrawing-iOS/AppDelegate.swift index 7cf52de..349e7f4 100644 --- a/FreehandDrawing-iOS/AppDelegate.swift +++ b/FreehandDrawing-iOS/AppDelegate.swift @@ -30,30 +30,30 @@ class AppDelegate: UIResponder, UIApplicationDelegate { var window: UIWindow? - func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool { + func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { // Override point for customization after application launch. return true } - func applicationWillResignActive(application: UIApplication) { + func applicationWillResignActive(_ application: UIApplication) { // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. } - func applicationDidEnterBackground(application: UIApplication) { + func applicationDidEnterBackground(_ application: UIApplication) { // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. } - func applicationWillEnterForeground(application: UIApplication) { + func applicationWillEnterForeground(_ application: UIApplication) { // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. } - func applicationDidBecomeActive(application: UIApplication) { + func applicationDidBecomeActive(_ application: UIApplication) { // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. } - func applicationWillTerminate(application: UIApplication) { + func applicationWillTerminate(_ application: UIApplication) { // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. } diff --git a/FreehandDrawing-iOS/CircleDrawCommand.swift b/FreehandDrawing-iOS/CircleDrawCommand.swift index 9c76a73..19c5c4e 100644 --- a/FreehandDrawing-iOS/CircleDrawCommand.swift +++ b/FreehandDrawing-iOS/CircleDrawCommand.swift @@ -32,10 +32,9 @@ struct CircleDrawCommand : DrawCommand { // MARK: DrawCommand - func execute(canvas: Canvas) { - CGContextSetFillColorWithColor(canvas.context, self.color.CGColor) - - CGContextAddArc(canvas.context, self.center.x, self.center.y, self.radius, 0, 2 * CGFloat(M_PI), 1) - CGContextFillPath(canvas.context) + func execute(_ canvas: Canvas) { + canvas.context.setFillColor(self.color.cgColor) + canvas.context.addArc(center: self.center, radius: self.radius, startAngle: 0, endAngle: 2 * CGFloat(M_PI), clockwise: true) + (canvas.context).fillPath() } -} \ No newline at end of file +} diff --git a/FreehandDrawing-iOS/ComposedCommand.swift b/FreehandDrawing-iOS/ComposedCommand.swift index ac84a61..824c60f 100644 --- a/FreehandDrawing-iOS/ComposedCommand.swift +++ b/FreehandDrawing-iOS/ComposedCommand.swift @@ -29,13 +29,13 @@ struct ComposedCommand : DrawCommand { // MARK: DrawCommand - func execute(canvas: Canvas) { + func execute(_ canvas: Canvas) { self.commands.map { $0.execute(canvas) } } - mutating func addCommand(command: DrawCommand) { + mutating func addCommand(_ command: DrawCommand) { self.commands.append(command) } - private var commands: [DrawCommand] -} \ No newline at end of file + fileprivate var commands: [DrawCommand] +} diff --git a/FreehandDrawing-iOS/DrawCommands.swift b/FreehandDrawing-iOS/DrawCommands.swift index ee97b67..de1b337 100644 --- a/FreehandDrawing-iOS/DrawCommands.swift +++ b/FreehandDrawing-iOS/DrawCommands.swift @@ -30,9 +30,9 @@ protocol Canvas { } protocol DrawCommand { - func execute(canvas: Canvas) + func execute(_ canvas: Canvas) } protocol DrawCommandReceiver { - func executeCommands(commands: [DrawCommand]) + func executeCommands(_ commands: [DrawCommand]) } diff --git a/FreehandDrawing-iOS/DrawView.swift b/FreehandDrawing-iOS/DrawView.swift index 736441f..23bb6cd 100644 --- a/FreehandDrawing-iOS/DrawView.swift +++ b/FreehandDrawing-iOS/DrawView.swift @@ -28,8 +28,8 @@ class DrawView : UIView, Canvas, DrawCommandReceiver { // MARK: Canvas - var context: CGContextRef { - return UIGraphicsGetCurrentContext() + var context: CGContext { + return UIGraphicsGetCurrentContext()! } func reset() { @@ -39,41 +39,41 @@ class DrawView : UIView, Canvas, DrawCommandReceiver { // MARK: DrawCommandReceiver - func executeCommands(commands: [DrawCommand]) { + func executeCommands(_ commands: [DrawCommand]) { autoreleasepool { self.buffer = drawInContext { context in commands.map { $0.execute(self) } } - self.layer.contents = self.buffer?.CGImage ?? nil + self.layer.contents = self.buffer?.cgImage ?? nil } } // MARK: General setup to draw. Reusing a buffer and returning a new one - private func drawInContext(code:(context: CGContextRef) -> Void) -> UIImage { + fileprivate func drawInContext(_ code:(_ context: CGContext) -> Void) -> UIImage { let size = self.bounds.size // Initialize a full size image. Opaque because we don't need to draw over anything. Will be more performant. UIGraphicsBeginImageContextWithOptions(size, true, 0) let context = UIGraphicsGetCurrentContext() - CGContextSetFillColorWithColor(context, self.backgroundColor?.CGColor ?? UIColor.whiteColor().CGColor) - CGContextFillRect(context, self.bounds) + context?.setFillColor(self.backgroundColor?.cgColor ?? UIColor.white.cgColor) + context?.fill(self.bounds) // Draw previous buffer first if let buffer = buffer { - buffer.drawInRect(self.bounds) + buffer.draw(in: self.bounds) } // Execute draw code - code(context: context) + code(context!) // Grab updated buffer and return it let image = UIGraphicsGetImageFromCurrentImageContext() UIGraphicsEndImageContext() - return image + return image! } - private var buffer: UIImage? + fileprivate var buffer: UIImage? } diff --git a/FreehandDrawing-iOS/DrawViewController.swift b/FreehandDrawing-iOS/DrawViewController.swift index d312035..503d966 100644 --- a/FreehandDrawing-iOS/DrawViewController.swift +++ b/FreehandDrawing-iOS/DrawViewController.swift @@ -43,7 +43,7 @@ class DrawViewController: UIViewController { return self.view as! DrawView } - private var drawController: FreehandDrawController! + fileprivate var drawController: FreehandDrawController! @IBOutlet var toolbar: Toolbar! } diff --git a/FreehandDrawing-iOS/FreehandDrawController.swift b/FreehandDrawing-iOS/FreehandDrawController.swift index 1c8f552..7533cd5 100644 --- a/FreehandDrawing-iOS/FreehandDrawController.swift +++ b/FreehandDrawing-iOS/FreehandDrawController.swift @@ -9,10 +9,10 @@ import UIKit class FreehandDrawController : NSObject { - var color: UIColor = UIColor.blackColor() + var color: UIColor = UIColor.black var width: CGFloat = 5.0 - required init(canvas: protocol, view: UIView) { + required init(canvas: Canvas & DrawCommandReceiver, view: UIView) { self.canvas = canvas super.init() @@ -31,48 +31,48 @@ class FreehandDrawController : NSObject { // MARK: Gestures - private func setupGestureRecognizersInView(view: UIView) { + fileprivate func setupGestureRecognizersInView(_ view: UIView) { // Pan gesture recognizer to track lines - let panRecognizer = UIPanGestureRecognizer(target: self, action: "handlePan:") + let panRecognizer = UIPanGestureRecognizer(target: self, action: #selector(FreehandDrawController.handlePan(_:))) view.addGestureRecognizer(panRecognizer) // Tap gesture recognizer to track points - let tapRecognizer = UITapGestureRecognizer(target: self, action: "handleTap:") + let tapRecognizer = UITapGestureRecognizer(target: self, action: #selector(FreehandDrawController.handleTap(_:))) view.addGestureRecognizer(tapRecognizer) } - @objc private func handlePan(sender: UIPanGestureRecognizer) { - let point = sender.locationInView(sender.view) + @objc fileprivate func handlePan(_ sender: UIPanGestureRecognizer) { + let point = sender.location(in: sender.view) switch sender.state { - case .Began: + case .began: self.startAtPoint(point) - case .Changed: - self.continueAtPoint(point, velocity: sender.velocityInView(sender.view)) - case .Ended: + case .changed: + self.continueAtPoint(point, velocity: sender.velocity(in: sender.view)) + case .ended: self.endAtPoint(point) - case .Failed: + case .failed: self.endAtPoint(point) default: assert(false, "State not handled") } } - @objc private func handleTap(sender: UITapGestureRecognizer) { - let point = sender.locationInView(sender.view) - if sender.state == .Ended { + @objc fileprivate func handleTap(_ sender: UITapGestureRecognizer) { + let point = sender.location(in: sender.view) + if sender.state == .ended { self.tapAtPoint(point) } } // MARK: Draw commands - private func startAtPoint(point: CGPoint) { + fileprivate func startAtPoint(_ point: CGPoint) { self.lastPoint = point self.lineStrokeCommand = ComposedCommand(commands: []) } - private func continueAtPoint(point: CGPoint, velocity: CGPoint) { - let segmentWidth = modulatedWidth(self.width, velocity, self.lastVelocity, self.lastWidth ?? self.width) + fileprivate func continueAtPoint(_ point: CGPoint, velocity: CGPoint) { + let segmentWidth = modulatedWidth(self.width, velocity: velocity, previousVelocity: self.lastVelocity, previousWidth: self.lastWidth ?? self.width) let segment = Segment(a: self.lastPoint, b: point, width: segmentWidth) let lineCommand = LineDrawCommand(current: segment, previous: lastSegment, width: segmentWidth, color: self.color) @@ -86,29 +86,29 @@ class FreehandDrawController : NSObject { self.lastWidth = segmentWidth } - private func endAtPoint(point: CGPoint) { + fileprivate func endAtPoint(_ point: CGPoint) { if let lineStrokeCommand = self.lineStrokeCommand { self.commandQueue.append(lineStrokeCommand) } - self.lastPoint = CGPointZero + self.lastPoint = CGPoint.zero self.lastSegment = nil - self.lastVelocity = CGPointZero + self.lastVelocity = CGPoint.zero self.lastWidth = nil self.lineStrokeCommand = nil } - private func tapAtPoint(point: CGPoint) { + fileprivate func tapAtPoint(_ point: CGPoint) { let circleCommand = CircleDrawCommand(center: point, radius: self.width/2.0, color: self.color) self.canvas.executeCommands([circleCommand]) self.commandQueue.append(circleCommand) } - private let canvas: protocol - private var lineStrokeCommand: ComposedCommand? - private var commandQueue: Array = [] - private var lastPoint: CGPoint = CGPointZero - private var lastSegment: Segment? - private var lastVelocity: CGPoint = CGPointZero - private var lastWidth: CGFloat? + fileprivate let canvas: Canvas & DrawCommandReceiver + fileprivate var lineStrokeCommand: ComposedCommand? + fileprivate var commandQueue: Array = [] + fileprivate var lastPoint: CGPoint = CGPoint.zero + fileprivate var lastSegment: Segment? + fileprivate var lastVelocity: CGPoint = CGPoint.zero + fileprivate var lastWidth: CGFloat? } diff --git a/FreehandDrawing-iOS/LineDrawCommand.swift b/FreehandDrawing-iOS/LineDrawCommand.swift index b05b699..6f30e4e 100644 --- a/FreehandDrawing-iOS/LineDrawCommand.swift +++ b/FreehandDrawing-iOS/LineDrawCommand.swift @@ -33,35 +33,35 @@ struct LineDrawCommand : DrawCommand { // MARK: DrawCommand - func execute(canvas: Canvas) { + func execute(_ canvas: Canvas) { self.configure(canvas) - if let previous = self.previous { + if self.previous != nil { self.drawQuadraticCurve(canvas) } else { self.drawLine(canvas) } } - private func configure(canvas: Canvas) { - CGContextSetStrokeColorWithColor(canvas.context, self.color.CGColor) - CGContextSetLineWidth(canvas.context, self.width) - CGContextSetLineCap(canvas.context, kCGLineCapRound) + fileprivate func configure(_ canvas: Canvas) { + canvas.context.setStrokeColor(self.color.cgColor) + canvas.context.setLineWidth(self.width) + (canvas.context).setLineCap(CGLineCap.round) } - private func drawLine(canvas: Canvas) { - CGContextMoveToPoint(canvas.context, self.current.a.x, self.current.a.y) - CGContextAddLineToPoint(canvas.context, self.current.b.x, self.current.b.y) - CGContextStrokePath(canvas.context) + fileprivate func drawLine(_ canvas: Canvas) { + canvas.context.move(to: CGPoint(x: self.current.a.x, y: self.current.a.y)) + canvas.context.addLine(to: CGPoint(x: self.current.b.x, y: self.current.b.y)) + canvas.context.strokePath() } - private func drawQuadraticCurve(canvas: Canvas) { + fileprivate func drawQuadraticCurve(_ canvas: Canvas) { if let previousMid = self.previous?.midPoint { let currentMid = self.current.midPoint - CGContextMoveToPoint(canvas.context, previousMid.x, previousMid.y) - CGContextAddQuadCurveToPoint(canvas.context, current.a.x, current.a.y, currentMid.x, currentMid.y) - CGContextStrokePath(canvas.context) + canvas.context.move(to: CGPoint(x: previousMid.x, y: previousMid.y)) + canvas.context.addQuadCurve(to: CGPoint(x:current.a.x, y:current.a.y), control: currentMid) + canvas.context.strokePath() } } -} \ No newline at end of file +} diff --git a/FreehandDrawing-iOS/Toolbar.swift b/FreehandDrawing-iOS/Toolbar.swift index 5da2e5b..5ac9d67 100644 --- a/FreehandDrawing-iOS/Toolbar.swift +++ b/FreehandDrawing-iOS/Toolbar.swift @@ -25,27 +25,27 @@ THE SOFTWARE. import UIKit class Toolbar : UIView { - typealias ColorChangeHandler = UIColor -> Void - typealias UndoHandler = Void->Void + typealias ColorChangeHandler = (UIColor) -> Void + typealias UndoHandler = (Void)->Void - required init(coder aDecoder: NSCoder) { + required init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder) } // Allows embedding a view in another xib or storyboard - override func awakeAfterUsingCoder(aDecoder: NSCoder) -> AnyObject? { + override func awakeAfter(using aDecoder: NSCoder) -> Any? { if self.subviews.count > 0 { return self; } - let mainBundle = NSBundle.mainBundle() - let loadedView: UIView = mainBundle.loadNibNamed("Toolbar", owner: nil, options: nil).first! as! UIView + let mainBundle = Bundle.main + let loadedView: UIView = mainBundle.loadNibNamed("Toolbar", owner: nil, options: nil)!.first! as! UIView loadedView.frame = self.frame; loadedView.autoresizingMask = self.autoresizingMask; - loadedView.setTranslatesAutoresizingMaskIntoConstraints(self.translatesAutoresizingMaskIntoConstraints()) + loadedView.translatesAutoresizingMaskIntoConstraints = true - for constraint in self.constraints() as! [NSLayoutConstraint] { + for constraint in self.constraints { let firstItem: AnyObject = constraint.firstItem as! NSObject == self ? loadedView : constraint.firstItem @@ -69,7 +69,7 @@ class Toolbar : UIView { // Add a tap gesture recognizer for every view let addTapRecognizer = { (view: UIView) -> UIView in - let tapRecognizer = UITapGestureRecognizer(target: self, action: "handleTap:") + let tapRecognizer = UITapGestureRecognizer(target: self, action: #selector(Toolbar.handleTap(_:))) view.addGestureRecognizer(tapRecognizer) return view } @@ -77,16 +77,16 @@ class Toolbar : UIView { let colorSelectors: [UIView] = [self.color1, self.color2, self.color3] colorSelectors.map(addTapRecognizer) - colorSelectors.map { $0.layer.cornerRadius = CGRectGetWidth($0.frame) / 2.0 } + colorSelectors.map { $0.layer.cornerRadius = $0.frame.width / 2.0 } } - @objc private func handleTap(sender: UITapGestureRecognizer) { - if sender.state == .Ended { - self.colorChangeHandler?(sender.view?.backgroundColor ?? UIColor.blackColor()) + @objc fileprivate func handleTap(_ sender: UITapGestureRecognizer) { + if sender.state == .ended { + self.colorChangeHandler?(sender.view?.backgroundColor ?? UIColor.black) } } - @IBAction private func undo() { + @IBAction fileprivate func undo() { self.undoHandler?() } diff --git a/FreehandDrawing-iOS/WidthModulation.swift b/FreehandDrawing-iOS/WidthModulation.swift index 1024992..3e0a9c1 100644 --- a/FreehandDrawing-iOS/WidthModulation.swift +++ b/FreehandDrawing-iOS/WidthModulation.swift @@ -24,14 +24,14 @@ THE SOFTWARE. import UIKit -func modulatedWidth(width: CGFloat, velocity: CGPoint, previousVelocity: CGPoint, previousWidth: CGFloat) -> CGFloat { +func modulatedWidth(_ width: CGFloat, velocity: CGPoint, previousVelocity: CGPoint, previousWidth: CGFloat) -> CGFloat { let velocityAdjustement: CGFloat = 600.0 let speed = velocity.length() / velocityAdjustement let previousSpeed = previousVelocity.length() / velocityAdjustement let modulated = width / (0.6 * speed + 0.4 * previousSpeed) - let limited = clamp(modulated, 0.75 * previousWidth, 1.25 * previousWidth) - let final = clamp(limited, 0.2*width, width) + let limited = clamp(modulated, min: 0.75 * previousWidth, max: 1.25 * previousWidth) + let final = clamp(limited, min: 0.2 * width, max: width) return final } @@ -42,7 +42,7 @@ extension CGPoint { } } -func clamp(value: T, min: T, max: T) -> T { +func clamp(_ value: T, min: T, max: T) -> T { if (value < min) { return min } @@ -52,4 +52,4 @@ func clamp(value: T, min: T, max: T) -> T { } return value -} \ No newline at end of file +} diff --git a/FreehandDrawing-iOSTests/FreehandDrawing_iOSTests.swift b/FreehandDrawing-iOSTests/FreehandDrawing_iOSTests.swift index ae65833..eebae50 100644 --- a/FreehandDrawing-iOSTests/FreehandDrawing_iOSTests.swift +++ b/FreehandDrawing-iOSTests/FreehandDrawing_iOSTests.swift @@ -28,7 +28,7 @@ class FreehandDrawing_iOSTests: XCTestCase { func testPerformanceExample() { // This is an example of a performance test case. - self.measureBlock() { + self.measure() { // Put the code you want to measure the time of here. } }