@@ -11,79 +11,59 @@ import UIKit
11@IBDesignable public class GMStepper: UIControl {
11@IBDesignable public class GMStepper: UIControl {
13 /// Current value of the stepper. Defaults to 0.
13 /// Current value of the stepper. Defaults to 0.
14− @objc @IBInspectable public var value: Double = 0 {
14+ public var value = 0 {
16 value = min(maximumValue, max(minimumValue, value))
16 value = min(maximumValue, max(minimumValue, value))
18− let isInteger = floor(value) == value
21− // If we have items, we will display them as steps
24− if isInteger && stepValue == 1.0 && items.count > 0 {
25− label.text = items[Int(value)]
27− else if showIntegerIfDoubleIsInteger && isInteger {
28− label.text = String(stringInterpolationSegment: Int(value))
30− label.text = String(stringInterpolationSegment: value)
17+ label.text = String(value)
33 if oldValue != value {
19 if oldValue != value {
34− sendActions(for: .valueChanged)
20+ sendActionsForControlEvents(.ValueChanged)
39 /// Minimum value. Must be less than maximumValue. Defaults to 0.
25 /// Minimum value. Must be less than maximumValue. Defaults to 0.
40− @objc @IBInspectable public var minimumValue: Double = 0 {
26+ @IBInspectable public var minimumValue: Int = 0 {
42− value = min(maximumValue, max(minimumValue, value))
28+ value = 0
46− /// Maximum value. Must be more than minimumValue. Defaults to 100.
32+ /// Maximum value. Must be more than minimumValue. Defaults to 10.
47− @objc @IBInspectable public var maximumValue: Double = 100 {
33+ @IBInspectable public var maximumValue: Int = 10 {
49− value = min(maximumValue, max(minimumValue, value))
35+ value = 0
53− /// Step/Increment value as in UIStepper. Defaults to 1.
54− @objc @IBInspectable public var stepValue: Double = 1
56− /// The same as UIStepper's autorepeat. If true, holding on the buttons or keeping the pan gesture alters the value repeatedly. Defaults to true.
39+ /// The same as UIStepper's autorepeat. If true, holding on the buttons or the pan gesture repeatedly alters value. Defaults to true.
57− @objc @IBInspectable public var autorepeat: Bool = true
40+ @IBInspectable public var autorepeat: Bool = true
59− /// If the value is integer, it is shown without floating point.
60− @objc @IBInspectable public var showIntegerIfDoubleIsInteger: Bool = true
62− /// Text on the left button. Be sure that it fits in the button. Defaults to "−".
42+ /// Text on the left button. Be sure that it fits in the button. Defaults to "-".
63− @objc @IBInspectable public var leftButtonText: String = "−" {
43+ @IBInspectable public var leftButtonText: String = "-" {
65− leftButton.setTitle(leftButtonText, for: .normal)
45+ leftButton.setTitle(leftButtonText, forState: .Normal)
69 /// Text on the right button. Be sure that it fits in the button. Defaults to "+".
49 /// Text on the right button. Be sure that it fits in the button. Defaults to "+".
70− @objc @IBInspectable public var rightButtonText: String = "+" {
50+ @IBInspectable public var rightButtonText: String = "+" {
72− rightButton.setTitle(rightButtonText, for: .normal)
52+ rightButton.setTitle(rightButtonText, forState: .Normal)
76 /// Text color of the buttons. Defaults to white.
56 /// Text color of the buttons. Defaults to white.
77− @objc @IBInspectable public var buttonsTextColor: UIColor = UIColor.white {
57+ @IBInspectable public var buttonsTextColor: UIColor = UIColor.whiteColor() {
79 for button in [leftButton, rightButton] {
59 for button in [leftButton, rightButton] {
80− button.setTitleColor(buttonsTextColor, for: .normal)
60+ button.setTitleColor(buttonsTextColor, forState: .Normal)
85 /// Background color of the buttons. Defaults to dark blue.
65 /// Background color of the buttons. Defaults to dark blue.
86− @objc @IBInspectable public var buttonsBackgroundColor: UIColor = UIColor(red:0.21, green:0.5, blue:0.74, alpha:1) {
66+ @IBInspectable public var buttonsBackgroundColor: UIColor = UIColor(red:0.21, green:0.5, blue:0.74, alpha:1) {
88 for button in [leftButton, rightButton] {
68 for button in [leftButton, rightButton] {
89 button.backgroundColor = buttonsBackgroundColor
69 button.backgroundColor = buttonsBackgroundColor
@@ -93,7 +73,7 @@ import UIKit
95 /// Font of the buttons. Defaults to AvenirNext-Bold, 20.0 points in size.
75 /// Font of the buttons. Defaults to AvenirNext-Bold, 20.0 points in size.
96− @objc public var buttonsFont = UIFont(name: "AvenirNext-Bold", size: 20.0)! {
76+ public var buttonsFont = UIFont(name: "AvenirNext-Bold", size: 20.0)! {
98 for button in [leftButton, rightButton] {
78 for button in [leftButton, rightButton] {
99 button.titleLabel?.font = buttonsFont
79 button.titleLabel?.font = buttonsFont
@@ -102,174 +82,70 @@ import UIKit
104 /// Text color of the middle label. Defaults to white.
84 /// Text color of the middle label. Defaults to white.
105− @objc @IBInspectable public var labelTextColor: UIColor = UIColor.white {
85+ @IBInspectable public var labelTextColor: UIColor = UIColor.whiteColor() {
107 label.textColor = labelTextColor
87 label.textColor = labelTextColor
111 /// Text color of the middle label. Defaults to lighter blue.
91 /// Text color of the middle label. Defaults to lighter blue.
112− @objc @IBInspectable public var labelBackgroundColor: UIColor = UIColor(red:0.26, green:0.6, blue:0.87, alpha:1) {
92+ @IBInspectable public var labelBackgroundColor: UIColor = UIColor(red:0.26, green:0.6, blue:0.87, alpha:1) {
114 label.backgroundColor = labelBackgroundColor
94 label.backgroundColor = labelBackgroundColor
118 /// Font of the middle label. Defaults to AvenirNext-Bold, 25.0 points in size.
98 /// Font of the middle label. Defaults to AvenirNext-Bold, 25.0 points in size.
119− @objc public var labelFont = UIFont(name: "AvenirNext-Bold", size: 25.0)! {
99+ public var labelFont = UIFont(name: "AvenirNext-Bold", size: 25.0)! {
121 label.font = labelFont
101 label.font = labelFont
124− /// Corner radius of the middle label. Defaults to 0.
125− @objc @IBInspectable public var labelCornerRadius: CGFloat = 0 {
127− label.layer.cornerRadius = labelCornerRadius
132 /// Corner radius of the stepper's layer. Defaults to 4.0.
105 /// Corner radius of the stepper's layer. Defaults to 4.0.
133− @objc @IBInspectable public var cornerRadius: CGFloat = 4.0 {
106+ @IBInspectable public var cornerRadius: CGFloat = 4.0 {
135 layer.cornerRadius = cornerRadius
108 layer.cornerRadius = cornerRadius
136 clipsToBounds = true
109 clipsToBounds = true
140− /// Border width of the stepper and middle label's layer. Defaults to 0.0.
141− @objc @IBInspectable public var borderWidth: CGFloat = 0.0 {
143− layer.borderWidth = borderWidth
144− label.layer.borderWidth = borderWidth
148− /// Color of the border of the stepper and middle label's layer. Defaults to clear color.
149− @objc @IBInspectable public var borderColor: UIColor = UIColor.clear {
151− layer.borderColor = borderColor.cgColor
152− label.layer.borderColor = borderColor.cgColor
156 /// Percentage of the middle label's width. Must be between 0 and 1. Defaults to 0.5. Be sure that it is wide enough to show the value.
113 /// Percentage of the middle label's width. Must be between 0 and 1. Defaults to 0.5. Be sure that it is wide enough to show the value.
157− @objc @IBInspectable public var labelWidthWeight: CGFloat = 0.5 {
114+ @IBInspectable public var labelWidthWeight: CGFloat = 0.5 {
159 labelWidthWeight = min(1, max(0, labelWidthWeight))
116 labelWidthWeight = min(1, max(0, labelWidthWeight))
160 setNeedsLayout()
117 setNeedsLayout()
164− /// Color of the flashing animation on the buttons in case the value hit the limit.
165− @objc @IBInspectable public var limitHitAnimationColor: UIColor = UIColor(red:0.26, green:0.6, blue:0.87, alpha:1)
168 Width of the sliding animation. When buttons clicked, the middle label does a slide animation towards to the clicked button. Defaults to 5.
122 Width of the sliding animation. When buttons clicked, the middle label does a slide animation towards to the clicked button. Defaults to 5.
170− let labelSlideLength: CGFloat = 5
124+ private let labelSlideLength: CGFloat = 5
172 /// Duration of the sliding animation
126 /// Duration of the sliding animation
173− let labelSlideDuration = TimeInterval(0.1)
127+ private let labelSlideDuration = NSTimeInterval(0.1)
175− /// Duration of the animation when the value hits the limit.
176− let limitHitAnimationDuration = TimeInterval(0.1)
178− lazy var leftButton: UIButton = {
179− let button = UIButton()
180− button.setTitle(self.leftButtonText, for: .normal)
181− button.setTitleColor(self.buttonsTextColor, for: .normal)
182− button.backgroundColor = self.buttonsBackgroundColor
183− button.titleLabel?.font = self.buttonsFont
184− button.addTarget(self, action: #selector(GMStepper.leftButtonTouchDown), for: .touchDown)
185− button.addTarget(self, action: #selector(GMStepper.buttonTouchUp), for: .touchUpInside)
186− button.addTarget(self, action: #selector(GMStepper.buttonTouchUp), for: .touchUpOutside)
187− button.addTarget(self, action: #selector(GMStepper.buttonTouchUp), for: .touchCancel)
191− lazy var rightButton: UIButton = {
129+ /// Duration of the flashing animation when the value hits the limit.
192− let button = UIButton()
130+ private let limitHitAnimationDuration = NSTimeInterval(0.1)
193− button.setTitle(self.rightButtonText, for: .normal)
194− button.setTitleColor(self.buttonsTextColor, for: .normal)
195− button.backgroundColor = self.buttonsBackgroundColor
196− button.titleLabel?.font = self.buttonsFont
197− button.addTarget(self, action: #selector(GMStepper.rightButtonTouchDown), for: .touchDown)
198− button.addTarget(self, action: #selector(GMStepper.buttonTouchUp), for: .touchUpInside)
199− button.addTarget(self, action: #selector(GMStepper.buttonTouchUp), for: .touchUpOutside)
200− button.addTarget(self, action: #selector(GMStepper.buttonTouchUp), for: .touchCancel)
204− lazy var label: UILabel = {
132+ /// Color of the flashing animation on the buttons in case the value hit the limit.
205− let label = UILabel()
133+ @IBInspectable public var limitHitAnimationColor: UIColor = UIColor(red:0.26, green:0.6, blue:0.87, alpha:1)
206− label.textAlignment = .center
207− if self.showIntegerIfDoubleIsInteger && floor(self.value) == self.value {
208− label.text = String(stringInterpolationSegment: Int(self.value))
210− label.text = String(stringInterpolationSegment: self.value)
212− label.textColor = self.labelTextColor
213− label.backgroundColor = self.labelBackgroundColor
214− label.font = self.labelFont
215− label.layer.cornerRadius = self.labelCornerRadius
216− label.layer.masksToBounds = true
217− label.isUserInteractionEnabled = true
218− let panRecognizer = UIPanGestureRecognizer(target: self, action: #selector(GMStepper.handlePan))
219− panRecognizer.maximumNumberOfTouches = 1
220− label.addGestureRecognizer(panRecognizer)
224− var labelOriginalCenter: CGPoint!
135+ private let leftButton = UIButton()
225− var labelMaximumCenterX: CGFloat!
136+ private let rightButton = UIButton()
226− var labelMinimumCenterX: CGFloat!
137+ private let label = UILabel()
228− enum LabelPanState {
139+ private var labelOriginalCenter: CGPoint!
229− case Stable, HitRightEdge, HitLeftEdge
140+ private var labelMaximumCenterX: CGFloat!
230− }
141+ private var labelMinimumCenterX: CGFloat!
231− var panState = LabelPanState.Stable
233− enum StepperState {
143+ private enum LabelPanState {
234− case Stable, ShouldIncrease, ShouldDecrease
144+ case Stale, HitRightEdge, HitLeftEdge
236− var stepperState = StepperState.Stable {
238− if stepperState != .Stable {
248− @objc public var items : [String] = [] {
250− let isInteger = floor(value) == value
253− // If we have items, we will display them as steps
256− if isInteger && stepValue == 1.0 && items.count > 0 {
258− var value = Int(self.value)
260− if value >= items.count {
261− value = items.count - 1
262− self.value = Double(value)
265− label.text = items[value]
146+ private var panState = LabelPanState.Stale
271− /// Timer used for autorepeat option
272− var timer: Timer?
148+ private var timer: NSTimer?
274 /** When UIStepper reaches its top speed, it alters the value with a time interval of ~0.05 sec.
150 /** When UIStepper reaches its top speed, it alters the value with a time interval of ~0.05 sec.
275 The user pressing and holding on the stepper repeatedly:
151 The user pressing and holding on the stepper repeatedly:
@@ -277,11 +153,11 @@ import UIKit
277 - For the next 1.5 sec, it changes the value every 0.1 sec.
153 - For the next 1.5 sec, it changes the value every 0.1 sec.
278 - Then, every 0.05 sec.
154 - Then, every 0.05 sec.
280− let timerInterval = TimeInterval(0.05)
156+ private let timerInterval = NSTimeInterval(0.05)
282 /// Check the handleTimerFire: function. While it is counting the number of fires, it decreases the mod value so that the value is altered more frequently.
158 /// Check the handleTimerFire: function. While it is counting the number of fires, it decreases the mod value so that the value is altered more frequently.
283− var timerFireCount = 0
159+ private var timerFireCount = 0
284− var timerFireCountModulo: Int {
160+ private var timerFireCountModulo: Int {
285 if timerFireCount > 80 {
161 if timerFireCount > 80 {
286 return 1 // 0.05 sec * 1 = 0.05 sec
162 return 1 // 0.05 sec * 1 = 0.05 sec
287 } else if timerFireCount > 50 {
163 } else if timerFireCount > 50 {
@@ -291,27 +167,61 @@ import UIKit
170+ lazy var printTimerGaps: () -> () = {
171+ var prevTime: CFAbsoluteTime?
174+ var now = CFAbsoluteTimeGetCurrent()
175+ if let prevTime = prevTime {
176+ println(now - prevTime)
294− @objc required public init?(coder aDecoder: NSCoder) {
182+ required public init(coder aDecoder: NSCoder) {
295 super.init(coder: aDecoder)
183 super.init(coder: aDecoder)
299− @objc public override init(frame: CGRect) {
187+ public override init(frame: CGRect) {
300 super.init(frame: frame)
188 super.init(frame: frame)
304− func setup() {
192+ private func setup() {
193+ leftButton.setTitle(leftButtonText, forState: .Normal)
194+ leftButton.setTitleColor(buttonsTextColor, forState: .Normal)
195+ leftButton.backgroundColor = buttonsBackgroundColor
196+ leftButton.titleLabel?.font = buttonsFont
197+ leftButton.addTarget(self, action: "leftButtonTouchDown:", forControlEvents: .TouchDown)
198+ leftButton.addTarget(self, action: "leftButtonTouchUp:", forControlEvents: UIControlEvents.TouchUpInside)
199+ leftButton.addTarget(self, action: "leftButtonTouchUp:", forControlEvents: UIControlEvents.TouchUpOutside)
305 addSubview(leftButton)
200 addSubview(leftButton)
202+ rightButton.setTitle(rightButtonText, forState: .Normal)
203+ rightButton.setTitleColor(buttonsTextColor, forState: .Normal)
204+ rightButton.backgroundColor = buttonsBackgroundColor
205+ rightButton.titleLabel?.font = buttonsFont
206+ rightButton.addTarget(self, action: "rightButtonTapped:", forControlEvents: .TouchDown)
207+ rightButton.addTarget(self, action: "rightButtonTouchUp:", forControlEvents: UIControlEvents.TouchUpInside)
208+ rightButton.addTarget(self, action: "rightButtonTouchUp:", forControlEvents: UIControlEvents.TouchUpOutside)
306 addSubview(rightButton)
209 addSubview(rightButton)
211+ label.textAlignment = .Center
212+ label.text = String(value)
213+ label.textColor = labelTextColor
214+ label.backgroundColor = labelBackgroundColor
215+ label.font = labelFont
307 addSubview(label)
216 addSubview(label)
309 backgroundColor = buttonsBackgroundColor
218 backgroundColor = buttonsBackgroundColor
310 layer.cornerRadius = cornerRadius
219 layer.cornerRadius = cornerRadius
311 clipsToBounds = true
220 clipsToBounds = true
312− labelOriginalCenter = label.center
314− NotificationCenter.default.addObserver(self, selector: #selector(GMStepper.reset), name: NSNotification.Name.UIApplicationWillResignActive, object: nil)
222+ let panRecognizer = UIPanGestureRecognizer(target: self, action: "handlePan:")
223+ label.userInteractionEnabled = true
224+ label.addGestureRecognizer(panRecognizer)
317 public override func layoutSubviews() {
227 public override func layoutSubviews() {
@@ -327,46 +237,16 @@ import UIKit
327 labelOriginalCenter = label.center
237 labelOriginalCenter = label.center
330− func updateValue() {
331− if stepperState == .ShouldIncrease {
333− } else if stepperState == .ShouldDecrease {
340− NotificationCenter.default.removeObserver(self)
343− /// Useful closure for logging the timer interval. You can call this in the timer handler to test the autorepeat option. Not used in the current implementation.
344−// lazy var printTimerGaps: () -> () = {
345−// var prevTime: CFAbsoluteTime?
348−// var now = CFAbsoluteTimeGetCurrent()
349−// if let prevTime = prevTime {
350−// print(now - prevTime)
358−extension GMStepper {
359− @objc func handlePan(gesture: UIPanGestureRecognizer) {
242+ @objc private func handlePan(gesture: UIPanGestureRecognizer) {
360 switch gesture.state {
243 switch gesture.state {
361− case .began:
244+ case .Changed:
362− leftButton.isEnabled = false
363− rightButton.isEnabled = false
365− let translation = gesture.translation(in: label)
245+ var translation = gesture.translationInView(label)
366− gesture.setTranslation(CGPoint.zero, in: label)
246+ gesture.setTranslation(CGPointZero, inView: label)
368− let slidingRight = gesture.velocity(in: label).x > 0
248+ var slidingRight = gesture.velocityInView(label).x > 0
369− let slidingLeft = gesture.velocity(in: label).x < 0
249+ var slidingLeft = gesture.velocityInView(label).x < 0
371 // Move the label with pan
251 // Move the label with pan
372 if slidingRight {
252 if slidingRight {
@@ -377,45 +257,44 @@ extension GMStepper {
378 // When the label hits the edges, increase/decrease value and change button backgrounds
258 // When the label hits the edges, increase/decrease value and change button backgrounds
379 if label.center.x == labelMaximumCenterX {
259 if label.center.x == labelMaximumCenterX {
380− // If not hit the right edge before, increase the value and start the timer. If already hit the edge, do nothing. Timer will handle it.
260+
261+ // Increase only once for each pan gesture
381 if panState != .HitRightEdge {
262 if panState != .HitRightEdge {
382− stepperState = .ShouldIncrease
263+ value += 1
264+ scheduleTimerWithUserInfo(rightButton)
383 panState = .HitRightEdge
265 panState = .HitRightEdge
386− animateLimitHitIfNeeded()
268+ if value == maximumValue {
269+ animateLimitHitForButton(rightButton)
387 } else if label.center.x == labelMinimumCenterX {
271 } else if label.center.x == labelMinimumCenterX {
388 if panState != .HitLeftEdge {
273 if panState != .HitLeftEdge {
389− stepperState = .ShouldDecrease
274+ value -= 1
275+ scheduleTimerWithUserInfo(leftButton)
390 panState = .HitLeftEdge
276 panState = .HitLeftEdge
393− animateLimitHitIfNeeded()
279+ if value == minimumValue {
280+ animateLimitHitForButton(leftButton)
395− panState = .Stable
283+ reset()
396− stepperState = .Stable
399− self.rightButton.backgroundColor = self.buttonsBackgroundColor
400− self.leftButton.backgroundColor = self.buttonsBackgroundColor
402− case .ended, .cancelled, .failed:
285+
409− @objc func reset() {
293+ private func reset() {
410− panState = .Stable
294+ panState = .Stale
411− stepperState = .Stable
412 resetTimer()
295 resetTimer()
414− leftButton.isEnabled = true
415− rightButton.isEnabled = true
416− label.isUserInteractionEnabled = true
418− UIView.animate(withDuration: self.labelSlideDuration, animations: {
297+ UIView.animateWithDuration(self.labelSlideDuration, animations: {
419 self.label.center = self.labelOriginalCenter
298 self.label.center = self.labelOriginalCenter
420 self.rightButton.backgroundColor = self.buttonsBackgroundColor
299 self.rightButton.backgroundColor = self.buttonsBackgroundColor
421 self.leftButton.backgroundColor = self.buttonsBackgroundColor
300 self.leftButton.backgroundColor = self.buttonsBackgroundColor
@@ -425,88 +304,90 @@ extension GMStepper {
426// MARK: Button Events
305// MARK: Button Events
427extension GMStepper {
306extension GMStepper {
428− @objc func leftButtonTouchDown(button: UIButton) {
307+ @objc private func leftButtonTouchDown(button: UIButton) {
429− rightButton.isEnabled = false
430− label.isUserInteractionEnabled = false
433 if value == minimumValue {
308 if value == minimumValue {
434− animateLimitHitIfNeeded()
309+ animateLimitHitForButton(leftButton)
436− stepperState = .ShouldDecrease
311+ value -= 1
313+ scheduleTimerWithUserInfo(leftButton)
437 animateSlideLeft()
315 animateSlideLeft()
442− @objc func rightButtonTouchDown(button: UIButton) {
319+ @objc private func leftButtonTouchUp(button: UIButton) {
443− leftButton.isEnabled = false
320+ reset()
444− label.isUserInteractionEnabled = false
321+ stopTimer()
324+ @objc private func rightButtonTapped(button: UIButton) {
447 if value == maximumValue {
325 if value == maximumValue {
448− animateLimitHitIfNeeded()
326+ animateLimitHitForButton(rightButton)
450− stepperState = .ShouldIncrease
328+ value += 1
330+ scheduleTimerWithUserInfo(rightButton)
451 animateSlideRight()
332 animateSlideRight()
455− @objc func buttonTouchUp(button: UIButton) {
336+ @objc private func rightButtonTouchUp(button: UIButton) {
460// MARK: Animations
342// MARK: Animations
461extension GMStepper {
343extension GMStepper {
463− func animateSlideLeft() {
345+ private func animateSlideLeft() {
464− UIView.animate(withDuration: labelSlideDuration) {
346+ UIView.animateWithDuration(labelSlideDuration) {
465 self.label.center.x -= self.labelSlideLength
347 self.label.center.x -= self.labelSlideLength
469− func animateSlideRight() {
351+ private func animateSlideRight() {
470− UIView.animate(withDuration: labelSlideDuration) {
352+ UIView.animateWithDuration(labelSlideDuration) {
471 self.label.center.x += self.labelSlideLength
353 self.label.center.x += self.labelSlideLength
475− func animateToOriginalPosition() {
357+ private func animateToOriginalPosition() {
476 if self.label.center != self.labelOriginalCenter {
358 if self.label.center != self.labelOriginalCenter {
477− UIView.animate(withDuration: labelSlideDuration) {
359+ UIView.animateWithDuration(labelSlideDuration) {
478 self.label.center = self.labelOriginalCenter
360 self.label.center = self.labelOriginalCenter
483− func animateLimitHitIfNeeded() {
484− if value == minimumValue {
485− animateLimitHitForButton(button: leftButton)
486− } else if value == maximumValue {
487− animateLimitHitForButton(button: rightButton)
491− func animateLimitHitForButton(button: UIButton){
365+ private func animateLimitHitForButton(button: UIButton){
492− UIView.animate(withDuration: limitHitAnimationDuration) {
366+ UIView.animateWithDuration(limitHitAnimationDuration) {
493 button.backgroundColor = self.limitHitAnimationColor
367 button.backgroundColor = self.limitHitAnimationColor
498// MARK: Timer
373// MARK: Timer
499extension GMStepper {
374extension GMStepper {
500− @objc func handleTimerFire(timer: Timer) {
375+ func handleTimerFire(timer: NSTimer) {
501 timerFireCount += 1
376 timerFireCount += 1
503 if timerFireCount % timerFireCountModulo == 0 {
377 if timerFireCount % timerFireCountModulo == 0 {
379+ if let button = timer.userInfo as? UIButton {
380+ if button == leftButton {
508− func scheduleTimer() {
389+ func scheduleTimerWithUserInfo(userInfo: AnyObject?) {
509− timer = Timer.scheduledTimer(timeInterval: timerInterval, target: self, selector: #selector(GMStepper.handleTimerFire), userInfo: nil, repeats: true)
390+ timer = NSTimer.scheduledTimerWithTimeInterval(timerInterval, target: self, selector: "handleTimerFire:", userInfo: userInfo, repeats: true)
512 func resetTimer() {
393 func resetTimer() {
@@ -518,4 +399,4 @@ extension GMStepper {