Skip to content

Instantly share code, notes, and snippets.

@akovalov
Created March 1, 2021 10:50
Show Gist options
  • Save akovalov/7b22735e1fb7f1117bf04659e214d785 to your computer and use it in GitHub Desktop.
Save akovalov/7b22735e1fb7f1117bf04659e214d785 to your computer and use it in GitHub Desktop.
//
// DownloadProgress.swift
//
import Foundation
class DownloadProgress {
// MARK: - Properties
var estimatedTimeRemaining: TimeInterval?
var onEstimatedTimeRemainingUpdate: ((_ time: TimeInterval?) -> Void)?
private(set) var progress: Progress?
private var remainingTimeTimer: Timer?
private let smoothingFactor: Double = 0.05
private var averageSpeed: Double = 0
private var lastSpeed: Int64 = 0
private var lastCompletedUnitCount: Int64 = 0
// MARK: - Lifecycle
init() {
startRemainingTimeTimer()
}
deinit {
stopRemainingTimeTimer()
}
// MARK: - Actions
func update(with progress: Progress) {
self.progress = progress
}
private func calculateTimeRemaining() {
guard let progress = self.progress else {
estimatedTimeRemaining = nil
return
}
lastSpeed = progress.completedUnitCount - lastCompletedUnitCount
lastCompletedUnitCount = progress.completedUnitCount
averageSpeed = smoothingFactor * Double(lastSpeed) + (1 - smoothingFactor) * averageSpeed
estimatedTimeRemaining = Double(progress.totalUnitCount - progress.completedUnitCount) / averageSpeed
onEstimatedTimeRemainingUpdate?(estimatedTimeRemaining)
}
// MARK: - Timer
private func startRemainingTimeTimer() {
remainingTimeTimer = Timer.scheduledTimer(withTimeInterval: 1, repeats: true) { [weak self] _ in
self?.calculateTimeRemaining()
}
}
private func stopRemainingTimeTimer() {
remainingTimeTimer?.invalidate()
remainingTimeTimer = nil
}
}
@akovalov
Copy link
Author

akovalov commented Mar 1, 2021

Download progress class for calculating download time remaining.
Usage:

// store an instance somewhere
private let downloadProgress = DownloadProgress()

// when a `Progress` swift object arrives (from Alamofire for example)
downloadProgress.update(with: progress)

// call manually at any time
downloadProgress.estimatedTimeRemaining

// or use callback 
downloadProgress.onEstimatedTimeRemainingUpdate = { [weak self] _ in
    self?.updateDownloadEstimatedTimeRemaining()
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment