@@ -23,10 +23,7 @@ open class URLSessionClient: NSObject, URLSessionDelegate, URLSessionTaskDelegat
2323 /// A completion block returning a result. On `.success` it will contain a tuple with non-nil `Data` and its corresponding `HTTPURLResponse`. On `.failure` it will contain an error.
2424 public typealias Completion = ( Result < ( Data , HTTPURLResponse ) , Error > ) -> Void
2525
26- private var completionBlocks = Atomic < [ Int : Completion ] > ( [ : ] )
27- private var rawCompletions = Atomic < [ Int : RawCompletion ] > ( [ : ] )
28- private var datas = Atomic < [ Int : Data ] > ( [ : ] )
29- private var responses = Atomic < [ Int : HTTPURLResponse ] > ( [ : ] )
26+ private var tasks = Atomic < [ Int : TaskData ] > ( [ : ] )
3027
3128 /// The raw URLSession being used for this client
3229 open private( set) var session : URLSession !
@@ -44,24 +41,22 @@ open class URLSessionClient: NSObject, URLSessionDelegate, URLSessionTaskDelegat
4441 delegateQueue: callbackQueue)
4542 }
4643
44+ deinit {
45+ self . clearAllTasks ( )
46+ }
47+
4748 /// Clears underlying dictionaries of any data related to a particular task identifier.
4849 ///
4950 /// - Parameter identifier: The identifier of the task to clear.
50- open func clearTask( with identifier: Int ) {
51- self . rawCompletions. value. removeValue ( forKey: identifier)
52- self . completionBlocks. value. removeValue ( forKey: identifier)
53- self . datas. value. removeValue ( forKey: identifier)
54- self . responses. value. removeValue ( forKey: identifier)
51+ open func clear( task identifier: Int ) {
52+ self . tasks. mutate { $0. removeValue ( forKey: identifier) }
5553 }
5654
5755 /// Clears underlying dictionaries of any data related to all tasks.
5856 ///
5957 /// Mostly useful for cleanup and/or after invalidation of the `URLSession`.
6058 open func clearAllTasks( ) {
61- self . rawCompletions. value. removeAll ( )
62- self . completionBlocks. value. removeAll ( )
63- self . datas. value. removeAll ( )
64- self . responses. value. removeAll ( )
59+ self . tasks. mutate { $0. removeAll ( ) }
6560 }
6661
6762 /// The main method to perform a request.
@@ -76,16 +71,15 @@ open class URLSessionClient: NSObject, URLSessionDelegate, URLSessionTaskDelegat
7671 open func sendRequest( _ request: URLRequest ,
7772 rawTaskCompletionHandler: RawCompletion ? = nil ,
7873 completion: @escaping Completion ) -> URLSessionTask {
79- let dataTask = self . session. dataTask ( with: request)
80- if let rawCompletion = rawTaskCompletionHandler {
81- self . rawCompletions. value [ dataTask. taskIdentifier] = rawCompletion
82- }
74+ let task = self . session. dataTask ( with: request)
75+ let taskData = TaskData ( rawCompletion: rawTaskCompletionHandler,
76+ completionBlock: completion)
8377
84- self . completionBlocks. value [ dataTask. taskIdentifier] = completion
85- self . datas. value [ dataTask. taskIdentifier] = Data ( )
86- dataTask. resume ( )
78+ self . tasks. mutate { $0 [ task. taskIdentifier] = taskData }
8779
88- return dataTask
80+ task. resume ( )
81+
82+ return task
8983 }
9084
9185 /// Cancels a given task and clears out its underlying data.
@@ -94,16 +88,16 @@ open class URLSessionClient: NSObject, URLSessionDelegate, URLSessionTaskDelegat
9488 ///
9589 /// - Parameter task: The task you wish to cancel.
9690 open func cancel( task: URLSessionTask ) {
97- self . clearTask ( with : task. taskIdentifier)
91+ self . clear ( task : task. taskIdentifier)
9892 task. cancel ( )
9993 }
10094
10195 // MARK: - URLSessionDelegate
10296
10397 open func urlSession( _ session: URLSession , didBecomeInvalidWithError error: Error ? ) {
10498 let finalError = error ?? URLSessionClientError . sessionBecameInvalidWithoutUnderlyingError
105- for block in self . completionBlocks . value. values {
106- block ( . failure( finalError) )
99+ for task in self . tasks . value. values {
100+ task . completionBlock ( . failure( finalError) )
107101 }
108102
109103 self . clearAllTasks ( )
@@ -145,38 +139,33 @@ open class URLSessionClient: NSObject, URLSessionDelegate, URLSessionTaskDelegat
145139 open func urlSession( _ session: URLSession ,
146140 task: URLSessionTask ,
147141 didCompleteWithError error: Error ? ) {
148- let taskIdentifier = task. taskIdentifier
149142 defer {
150- self . clearTask ( with : taskIdentifier)
143+ self . clear ( task : task . taskIdentifier)
151144 }
152145
153- guard let completion = self . completionBlocks . value. removeValue ( forKey : taskIdentifier) else {
146+ guard let taskData = self . tasks . value [ task . taskIdentifier] else {
154147 // No completion blocks, the task has likely been cancelled. Bail out.
155148 return
156149 }
157150
158- let data = self . datas . value [ taskIdentifier ]
159- let response = self . responses . value [ taskIdentifier ]
151+ let data = taskData . data
152+ let response = taskData . response
160153
161- if let rawCompletion = self . rawCompletions . value . removeValue ( forKey : taskIdentifier ) {
154+ if let rawCompletion = taskData . rawCompletion {
162155 rawCompletion ( data, response, error)
163156 }
164157
165- guard let finalData = data else {
166- // Data is immediately created for a task on creation, so if it's not there, something's gone wrong.
167- completion ( . failure( URLSessionClientError . dataForRequestNotFound ( request: task. originalRequest) ) )
168- return
169- }
158+ let completion = taskData. completionBlock
170159
171160 if let finalError = error {
172- completion ( . failure( URLSessionClientError . networkError ( data: finalData , response: response, underlying: finalError) ) )
161+ completion ( . failure( URLSessionClientError . networkError ( data: data , response: response, underlying: finalError) ) )
173162 } else {
174163 guard let finalResponse = response else {
175164 completion ( . failure( URLSessionClientError . noHTTPResponse ( request: task. originalRequest) ) )
176165 return
177166 }
178167
179- completion ( . success( ( finalData , finalResponse) ) )
168+ completion ( . success( ( data , finalResponse) ) )
180169 }
181170 }
182171
@@ -215,7 +204,14 @@ open class URLSessionClient: NSObject, URLSessionDelegate, URLSessionTaskDelegat
215204 open func urlSession( _ session: URLSession ,
216205 dataTask: URLSessionDataTask ,
217206 didReceive data: Data ) {
218- self . datas. value [ dataTask. taskIdentifier] ? . append ( data)
207+ self . tasks. mutate {
208+ guard let taskData = $0 [ dataTask. taskIdentifier] else {
209+ assertionFailure ( " No data found for task \( dataTask. taskIdentifier) , cannot append received data " )
210+ return
211+ }
212+
213+ taskData. append ( additionalData: data)
214+ }
219215 }
220216
221217 @available ( iOS 9 . 0 , OSXApplicationExtension 10 . 11 , OSX 10 . 11 , * )
@@ -246,8 +242,12 @@ open class URLSessionClient: NSObject, URLSessionDelegate, URLSessionTaskDelegat
246242 completionHandler ( . allow)
247243 }
248244
249- if let httpResponse = response as? HTTPURLResponse {
250- self . responses. value [ dataTask. taskIdentifier] = httpResponse
245+ self . tasks. mutate {
246+ guard let taskData = $0 [ dataTask. taskIdentifier] else {
247+ return
248+ }
249+
250+ taskData. responseReceived ( response: response)
251251 }
252252 }
253253}
0 commit comments