Skip to content

Instantly share code, notes, and snippets.

@harshvishu
Last active February 6, 2021 11:56
Show Gist options
  • Save harshvishu/7228837fc3fb1ceebbde24ab9a6fd356 to your computer and use it in GitHub Desktop.
Save harshvishu/7228837fc3fb1ceebbde24ab9a6fd356 to your computer and use it in GitHub Desktop.
//
// CountDownTimer.swift
//
// Created by Harsh Vishwakarma.
//
import Foundation
import UIKit
final class CountDownTimer: NSObject, CountDown {
// - 1
// Initializes the timer to stop after given time limit
init(endsAfter timeLimit: TimeInterval, repeatingTask: CompletionHandler?, completion: CompletionHandler?) {
self.timeLimit = timeLimit
self.repeatingTask = repeatingTask
self.completion = completion
self.timeElapsed = 0.0
self.lastExecutionTime = Date()
}
// Uses Date object. If you want to countdown to a particular date/time
init(endsOn date: Date, repeatingTask: CompletionHandler?, completion: CompletionHandler?) {
self.timeLimit = date.timeIntervalSinceNow
self.repeatingTask = repeatingTask
self.completion = completion
self.timeElapsed = 0.0
self.lastExecutionTime = Date()
}
// - 2
var timeElapsed: TimeInterval {
didSet {
guard timeElapsed > 0 else {return}
if timeLimit - timeElapsed <= 0 {
completion?()
stop() // stop timer
}
}
}
var timeLimit: TimeInterval {
didSet {
// Reset
reset()
}
}
var isFinished: Bool {
return timeLimit - timeElapsed <= 0
}
var isRunning: Bool {
return !(displayLink?.isPaused ?? true)
}
var completion: CompletionHandler?
var repeatingTask: CompletionHandler?
private var lastExecutionTime: Date
private weak var displayLink: CADisplayLink?
// - 3
func start() {
self.lastExecutionTime = Date()
let displayLink = CADisplayLink(target: self, selector: #selector(refreshStats))
displayLink.add(to: .current, forMode: RunLoop.Mode.common)
self.displayLink = displayLink
}
func stop() {
displayLink?.invalidate()
}
func reset() {
displayLink?.invalidate()
timeElapsed = 0
}
func restart() {
self.reset()
self.start()
}
// Called every iteration
@objc private func refreshStats() {
guard !isFinished else {return}
let now = Date()
let elapsedTime = now.timeIntervalSince1970 - lastExecutionTime.timeIntervalSince1970
self.timeElapsed += elapsedTime
lastExecutionTime = now
repeatingTask?()
}
// - 4
deinit {
displayLink?.invalidate()
repeatingTask = nil
completion = nil
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment