Skip to content

Commit 0c7d339

Browse files
andriydrukAnton Pogonets
authored andcommitted
Dev: implement invalidateAndCancel
1 parent 6283662 commit 0c7d339

File tree

3 files changed

+51
-9
lines changed

3 files changed

+51
-9
lines changed

Foundation/URLSession/TaskRegistry.swift

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,15 @@ extension URLSession._TaskRegistry {
8686
allTasksFinished()
8787
}
8888
}
89+
90+
/// Cancel all tasks
91+
///
92+
/// - Note: This must **only** be accessed on the owning session's work queue.
93+
func cancelAllTasks() {
94+
for (_, task) in self.tasks {
95+
task._cancel()
96+
}
97+
}
8998

9099
func notify(on tasksCompetion: @escaping () -> Void) {
91100
tasksFinishedCallback = tasksCompetion

Foundation/URLSession/URLSession.swift

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -316,7 +316,32 @@ open class URLSession : NSObject {
316316
* cancellation is subject to the state of the task, and some tasks may
317317
* have already have completed at the time they are sent -cancel.
318318
*/
319-
open func invalidateAndCancel() { NSUnimplemented() }
319+
open func invalidateAndCancel() {
320+
//we need to return immediately
321+
workQueue.async {
322+
323+
//don't allow creation of new tasks from this point onwards
324+
self.invalidated = true
325+
326+
let invalidateSessionCallback = { [weak self] in
327+
//invoke the delegate method and break the delegate link
328+
guard let `self` = self, let sessionDelegate = self.delegate else { return }
329+
self.delegateQueue.addOperation {
330+
sessionDelegate.urlSession(self, didBecomeInvalidWithError: nil)
331+
self.delegate = nil
332+
}
333+
}
334+
335+
//wait for running tasks to finish
336+
if !self.taskRegistry.isEmpty {
337+
self.taskRegistry.notify(on: invalidateSessionCallback)
338+
self.taskRegistry.cancelAllTasks()
339+
} else {
340+
invalidateSessionCallback()
341+
}
342+
}
343+
344+
}
320345

321346
open func reset(completionHandler: @escaping () -> Void) { NSUnimplemented() } /* empty all cookies, cache and credential stores, removes disk files, issues -flushWithCompletionHandler:. Invokes completionHandler() on the delegate queue if not nil. */
322347

Foundation/URLSession/URLSessionTask.swift

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -182,14 +182,7 @@ open class URLSessionTask : NSObject, NSCopying {
182182
*/
183183
open func cancel() {
184184
workQueue.sync {
185-
guard self.state == .running || self.state == .suspended else { return }
186-
self.state = .canceling
187-
self.workQueue.async {
188-
let urlError = URLError(_nsError: NSError(domain: NSURLErrorDomain, code: NSURLErrorCancelled, userInfo: nil))
189-
self.error = urlError
190-
self._protocol?.stopLoading()
191-
self._protocol?.client?.urlProtocol(self._protocol!, didFailWithError: urlError)
192-
}
185+
self._cancel()
193186
}
194187
}
195188

@@ -305,6 +298,21 @@ open class URLSessionTask : NSObject, NSCopying {
305298
fileprivate var _priority: Float = URLSessionTask.defaultPriority
306299
}
307300

301+
internal extension URLSessionTask {
302+
303+
func _cancel() {
304+
guard self.state == .running || self.state == .suspended else { return }
305+
self.state = .canceling
306+
self.workQueue.async {
307+
let urlError = URLError(_nsError: NSError(domain: NSURLErrorDomain, code: NSURLErrorCancelled, userInfo: nil))
308+
self.error = urlError
309+
self._protocol?.stopLoading()
310+
self._protocol?.client?.urlProtocol(self._protocol!, didFailWithError: urlError)
311+
}
312+
}
313+
314+
}
315+
308316
extension URLSessionTask {
309317
public enum State : Int {
310318
/// The task is currently being serviced by the session

0 commit comments

Comments
 (0)