@@ -16,6 +16,13 @@ public typealias Percentage = Double
1616/// Guaranteed to be called back on the main thread
1717public typealias ProgressHandler = ( Percentage ) -> Void
1818
19+ /// Asynchronous completion handler that is called when a response is received for an upload
20+ public typealias FileUploadHandler = ( Data ) -> Void
21+
22+ /// Asynchronous cancellation handler that is called when an upload request is cancelled
23+ /// This can be used with the cancellationHandler attribute of the Progress object associated with the upload task
24+ public typealias CancellationHandler = ( ) -> Void
25+
1926/// Asynchronous completion handler that reports the status of request.
2027///
2128/// Guaranteed to be called back on a background thread (because the system erases the temporary file)
@@ -29,6 +36,7 @@ public typealias FileDownloadHandler = (Result<URL, Error>) -> Void
2936internal class FileProgress : NSObject {
3037 /// Stores the progress handlers to be called, keyed by unique task identifier
3138 private var progressHandlersByTaskID : [ Int : ProgressHandler ] = [ : ]
39+ private var uploadHandlerByTaskID : [ Int : FileUploadHandler ] = [ : ]
3240 private var downloadHandlersByTaskID : [ Int : FileDownloadHandler ] = [ : ]
3341
3442 /// Updates the progress handler for the specified task with the percentage value
@@ -41,6 +49,17 @@ internal class FileProgress: NSObject {
4149 progressHandler ( percent)
4250 }
4351 }
52+
53+ /// Invokes the completion handler for the specified task with the response data
54+ /// - Parameters:
55+ /// - data: the response data that can be decoded for custom responses such as error messages
56+ /// - taskIdentifier: unique task identifier
57+ func receive( data: Data , forKey taskIdentifier: Int ) {
58+ guard let completionHandler = uploadHandlerByTaskID [ taskIdentifier] else { return }
59+ DispatchQueue . main. async {
60+ completionHandler ( data)
61+ }
62+ }
4463
4564 /// Updates the request status for the specified task with the file URL
4665 /// - Parameters:
@@ -53,16 +72,32 @@ internal class FileProgress: NSObject {
5372 completionhandler ( result)
5473 }
5574
56- /// Registers a data task for file progress.
75+ /// Registers a data task for file progress of either an upload or download .
5776 /// - Parameters:
5877 /// - cancelable: optional cancelable task
5978 /// - progress: optional progress handler
60- func register( _ cancelable: Cancelable ? , progress: ProgressHandler ? ) {
79+ func registerProgress(
80+ _ cancelable: Cancelable ? ,
81+ progress: ProgressHandler ?
82+ ) {
6183 guard let task = cancelable as? URLSessionTask ,
6284 let progress = progress else { return }
6385 progressHandlersByTaskID [ task. taskIdentifier] = progress
6486 }
6587
88+ /// Registers the data task with a completion handler to be called when the response to the upload is received.
89+ /// - Parameters:
90+ /// - cancelable: optional cancelable task
91+ /// - completion: optional completion handler
92+ func registerCompletion(
93+ _ cancelable: Cancelable ? ,
94+ completion: FileUploadHandler ?
95+ ) {
96+ guard let task = cancelable as? URLSessionTask ,
97+ let completion = completion else { return }
98+ uploadHandlerByTaskID [ task. taskIdentifier] = completion
99+ }
100+
66101 /// Registers a data task for file progress.
67102 /// - Parameters:
68103 /// - cancelable: optional cancelable task
@@ -73,17 +108,37 @@ internal class FileProgress: NSObject {
73108 progress: ProgressHandler ? ,
74109 handler: @escaping FileDownloadHandler
75110 ) {
76- register ( cancelable, progress: progress)
111+ registerProgress ( cancelable, progress: progress)
77112 guard let task = cancelable as? URLSessionTask else { return }
78113 downloadHandlersByTaskID [ task. taskIdentifier] = handler
79114 }
115+
116+ /// Registers a data task for file upload progress and completion.
117+ /// - Parameters:
118+ /// - cancelable: optional cancelable task
119+ /// - progress: optional progress handler
120+ /// - completion: optional completion handler
121+ func registerUpload(
122+ _ cancelable: Cancelable ? ,
123+ progress: ProgressHandler ? ,
124+ completion: FileUploadHandler ?
125+ ) {
126+ registerProgress ( cancelable, progress: progress)
127+ registerCompletion ( cancelable, completion: completion)
128+ }
80129
81130 /// Unregisters a data task for file progress
82131 /// - Parameter taskIdentifier: unique task identifier
83132 func unregister( forKey taskIdentifier: Int ) {
84133 progressHandlersByTaskID. removeValue ( forKey: taskIdentifier)
85134 downloadHandlersByTaskID. removeValue ( forKey: taskIdentifier)
86135 }
136+
137+ /// Unregisters a completion handler, should be called once the final response is received
138+ /// - Parameter taskIdentifier: unique task identifier
139+ func unregisterUploadCompletion( forKey taskIdentifier: Int ) {
140+ uploadHandlerByTaskID. removeValue ( forKey: taskIdentifier)
141+ }
87142
88143 func checkResponseForError( task: URLSessionTask ) -> Error ? {
89144 guard let httpResponse = task. response as? HTTPURLResponse else {
0 commit comments