Created
February 24, 2018 19:35
-
-
Save hurshagrawal/96bc8fc4ba4942f7478bae931d7c6522 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/// Manager of asynchronous download `Operation` objects | |
class DownloadManager: NSObject { | |
/// Dictionary of operations, keyed by the `taskIdentifier` of the `URLSessionTask` | |
fileprivate var operations = [Int: DownloadOperation]() | |
/// Serial NSOperationQueue for downloads | |
private let queue: OperationQueue = { | |
let _queue = OperationQueue() | |
_queue.name = "download" | |
_queue.maxConcurrentOperationCount = 1 // I'd usually use values like 3 or 4 for performance reasons, but OP asked about downloading one at a time | |
return _queue | |
}() | |
/// Delegate-based NSURLSession for DownloadManager | |
lazy var session: URLSession = { | |
let configuration = URLSessionConfiguration.default | |
return URLSession(configuration: configuration, delegate: self, delegateQueue: nil) | |
}() | |
/// Add download | |
/// | |
/// - parameter URL: The URL of the file to be downloaded | |
/// | |
/// - returns: The DownloadOperation of the operation that was queued | |
@discardableResult | |
func addDownload(_ url: URL) -> DownloadOperation { | |
let operation = DownloadOperation(session: session, url: url) | |
operations[operation.task.taskIdentifier] = operation | |
queue.addOperation(operation) | |
return operation | |
} | |
/// Cancel all queued operations | |
func cancelAll() { | |
queue.cancelAllOperations() | |
} | |
} | |
// MARK: URLSessionDownloadDelegate methods | |
extension DownloadManager: URLSessionDownloadDelegate { | |
func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didFinishDownloadingTo location: URL) { | |
operations[downloadTask.taskIdentifier]?.urlSession(session, downloadTask: downloadTask, didFinishDownloadingTo: location) | |
} | |
func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didWriteData bytesWritten: Int64, totalBytesWritten: Int64, totalBytesExpectedToWrite: Int64) { | |
operations[downloadTask.taskIdentifier]?.urlSession(session, downloadTask: downloadTask, didWriteData: bytesWritten, totalBytesWritten: totalBytesWritten, totalBytesExpectedToWrite: totalBytesExpectedToWrite) | |
} | |
} | |
// MARK: URLSessionTaskDelegate methods | |
extension DownloadManager: URLSessionTaskDelegate { | |
func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) { | |
let key = task.taskIdentifier | |
operations[key]?.urlSession(session, task: task, didCompleteWithError: error) | |
operations.removeValue(forKey: key) | |
} | |
} | |
/// Asynchronous Operation subclass for downloading | |
class DownloadOperation : AsynchronousOperation { | |
let task: URLSessionTask | |
init(session: URLSession, url: URL) { | |
task = session.downloadTask(with: url) | |
super.init() | |
} | |
override func cancel() { | |
task.cancel() | |
super.cancel() | |
} | |
override func main() { | |
task.resume() | |
} | |
} | |
// MARK: NSURLSessionDownloadDelegate methods | |
extension DownloadOperation: URLSessionDownloadDelegate { | |
func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didFinishDownloadingTo location: URL) { | |
do { | |
let manager = FileManager.default | |
let destinationURL = try manager.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: false) | |
.appendingPathComponent(downloadTask.originalRequest!.url!.lastPathComponent) | |
if manager.fileExists(atPath: destinationURL.path) { | |
try manager.removeItem(at: destinationURL) | |
} | |
try manager.moveItem(at: location, to: destinationURL) | |
} catch { | |
print("\(error)") | |
} | |
} | |
func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didWriteData bytesWritten: Int64, totalBytesWritten: Int64, totalBytesExpectedToWrite: Int64) { | |
let progress = Double(totalBytesWritten) / Double(totalBytesExpectedToWrite) | |
print("\(downloadTask.originalRequest!.url!.absoluteString) \(progress)") | |
} | |
} | |
// MARK: NSURLSessionTaskDelegate methods | |
extension DownloadOperation: URLSessionTaskDelegate { | |
func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) { | |
completeOperation() | |
if error != nil { | |
print("\(error)") | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment