@@ -16,6 +16,13 @@ public typealias Percentage = Double
16
16
/// Guaranteed to be called back on the main thread
17
17
public typealias ProgressHandler = ( Percentage ) -> Void
18
18
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
+
19
26
/// Asynchronous completion handler that reports the status of request.
20
27
///
21
28
/// 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
29
36
internal class FileProgress : NSObject {
30
37
/// Stores the progress handlers to be called, keyed by unique task identifier
31
38
private var progressHandlersByTaskID : [ Int : ProgressHandler ] = [ : ]
39
+ private var uploadHandlerByTaskID : [ Int : FileUploadHandler ] = [ : ]
32
40
private var downloadHandlersByTaskID : [ Int : FileDownloadHandler ] = [ : ]
33
41
34
42
/// Updates the progress handler for the specified task with the percentage value
@@ -41,6 +49,17 @@ internal class FileProgress: NSObject {
41
49
progressHandler ( percent)
42
50
}
43
51
}
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
+ }
44
63
45
64
/// Updates the request status for the specified task with the file URL
46
65
/// - Parameters:
@@ -53,16 +72,32 @@ internal class FileProgress: NSObject {
53
72
completionhandler ( result)
54
73
}
55
74
56
- /// Registers a data task for file progress.
75
+ /// Registers a data task for file progress of either an upload or download .
57
76
/// - Parameters:
58
77
/// - cancelable: optional cancelable task
59
78
/// - progress: optional progress handler
60
- func register( _ cancelable: Cancelable ? , progress: ProgressHandler ? ) {
79
+ func registerProgress(
80
+ _ cancelable: Cancelable ? ,
81
+ progress: ProgressHandler ?
82
+ ) {
61
83
guard let task = cancelable as? URLSessionTask ,
62
84
let progress = progress else { return }
63
85
progressHandlersByTaskID [ task. taskIdentifier] = progress
64
86
}
65
87
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
+
66
101
/// Registers a data task for file progress.
67
102
/// - Parameters:
68
103
/// - cancelable: optional cancelable task
@@ -73,17 +108,37 @@ internal class FileProgress: NSObject {
73
108
progress: ProgressHandler ? ,
74
109
handler: @escaping FileDownloadHandler
75
110
) {
76
- register ( cancelable, progress: progress)
111
+ registerProgress ( cancelable, progress: progress)
77
112
guard let task = cancelable as? URLSessionTask else { return }
78
113
downloadHandlersByTaskID [ task. taskIdentifier] = handler
79
114
}
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
+ }
80
129
81
130
/// Unregisters a data task for file progress
82
131
/// - Parameter taskIdentifier: unique task identifier
83
132
func unregister( forKey taskIdentifier: Int ) {
84
133
progressHandlersByTaskID. removeValue ( forKey: taskIdentifier)
85
134
downloadHandlersByTaskID. removeValue ( forKey: taskIdentifier)
86
135
}
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
+ }
87
142
88
143
func checkResponseForError( task: URLSessionTask ) -> Error ? {
89
144
guard let httpResponse = task. response as? HTTPURLResponse else {
0 commit comments