Last active
April 16, 2021 02:47
-
-
Save donnywals/4e946402619af5b20dca541cf89fda4f to your computer and use it in GitHub Desktop.
This file contains hidden or 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
class UploadTaskPublisher { | |
typealias UploadProgress = (bytesSent: Int64, expectedTotalBytes: Int64) | |
typealias ProgressSubject = CurrentValueSubject<UploadProgress, Never> | |
typealias CompletionSubject = PassthroughSubject<URLSession.DataTaskPublisher.Output, URLSession.DataTaskPublisher.Failure> | |
var progress = ProgressSubject((0, 0)) | |
var completion = CompletionSubject() | |
} | |
class UploadSession: NSObject, URLSessionTaskDelegate { | |
static var shared = UploadSession() | |
private var publishers = [URLSessionTask: UploadTaskPublisher]() | |
lazy private var session = URLSession(configuration: .default, | |
delegate: self, | |
delegateQueue: nil) | |
/// Starts an upload task and prepares an UploadTaskPublisher that provides progress and completion subjects | |
/// - Parameter request: The URLRequest to run | |
/// - Returns: an UploadTaskPublisher that provides progress and completion subjects | |
func performTask(with request: URLRequest) -> UploadTaskPublisher { | |
let publisher = UploadTaskPublisher() | |
let task = session.uploadTask(with: request, from: nil) { data, response, error in | |
if let data = data, let response = response { | |
publisher.completion.send((data, response)) | |
publisher.completion.send(completion: .finished) | |
} else if let error = error as? URLError { | |
publisher.completion.send(completion: .failure(error)) | |
} else { | |
fatalError("Task completed without a valid output") | |
} | |
} | |
publishers[task] = publisher | |
task.resume() | |
return publisher | |
} | |
func urlSession(_ session: URLSession, task: URLSessionTask, | |
didSendBodyData bytesSent: Int64, totalBytesSent: Int64, | |
totalBytesExpectedToSend: Int64) { | |
guard let publisher = publishers[task] else { | |
return | |
} | |
publisher.progress.value = (totalBytesSent, totalBytesExpectedToSend) | |
} | |
} | |
// simple usage example. I'm assuming you have a request prepared | |
let publisher = UploadSession.shared.performTask(with: aRequest) | |
publisher.progress.sink { progress in | |
// calculate progress based on progress.bytesSent / progress.expectedTotalBytes | |
} | |
publisher.completion.sink { result in | |
// handle the server response if needed | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment