@@ -9,7 +9,7 @@ import FoundationNetworking
9
9
10
10
// A simple URLSession wrapper adding async/await APIs compatible with older platforms.
11
11
final class DataLoader : NSObject , URLSessionDataDelegate , URLSessionDownloadDelegate , @unchecked Sendable {
12
- private var handlers = [ URLSessionTask : TaskHandler ] ( )
12
+ private let handlers = TaskHandlersDictionary ( )
13
13
14
14
var userSessionDelegate : URLSessionDelegate ? {
15
15
didSet {
@@ -31,11 +31,10 @@ final class DataLoader: NSObject, URLSessionDataDelegate, URLSessionDownloadDele
31
31
func startDataTask( _ task: URLSessionDataTask , session: URLSession , delegate: URLSessionDataDelegate ? ) async throws -> Response < Data > {
32
32
try await withTaskCancellationHandler ( handler: { task. cancel ( ) } ) {
33
33
try await withUnsafeThrowingContinuation { continuation in
34
- session. delegateQueue. addOperation {
35
- let handler = DataTaskHandler ( delegate: delegate)
36
- handler. completion = continuation. resume ( with: )
37
- self . handlers [ task] = handler
38
- }
34
+ let handler = DataTaskHandler ( delegate: delegate)
35
+ handler. completion = continuation. resume ( with: )
36
+ self . handlers [ task] = handler
37
+
39
38
task. resume ( )
40
39
}
41
40
}
@@ -44,11 +43,10 @@ final class DataLoader: NSObject, URLSessionDataDelegate, URLSessionDownloadDele
44
43
func startDownloadTask( _ task: URLSessionDownloadTask , session: URLSession , delegate: URLSessionDownloadDelegate ? ) async throws -> Response < URL > {
45
44
try await withTaskCancellationHandler ( handler: { task. cancel ( ) } ) {
46
45
try await withUnsafeThrowingContinuation { continuation in
47
- session. delegateQueue. addOperation {
48
- let handler = DownloadTaskHandler ( delegate: delegate)
49
- handler. completion = continuation. resume ( with: )
50
- self . handlers [ task] = handler
51
- }
46
+ let handler = DownloadTaskHandler ( delegate: delegate)
47
+ handler. completion = continuation. resume ( with: )
48
+ self . handlers [ task] = handler
49
+
52
50
task. resume ( )
53
51
}
54
52
}
@@ -57,11 +55,10 @@ final class DataLoader: NSObject, URLSessionDataDelegate, URLSessionDownloadDele
57
55
func startUploadTask( _ task: URLSessionUploadTask , session: URLSession , delegate: URLSessionTaskDelegate ? ) async throws -> Response < Data > {
58
56
try await withTaskCancellationHandler ( handler: { task. cancel ( ) } ) {
59
57
try await withUnsafeThrowingContinuation { continuation in
60
- session. delegateQueue. addOperation {
61
- let handler = DataTaskHandler ( delegate: delegate)
62
- handler. completion = continuation. resume ( with: )
63
- self . handlers [ task] = handler
64
- }
58
+ let handler = DataTaskHandler ( delegate: delegate)
59
+ handler. completion = continuation. resume ( with: )
60
+ self . handlers [ task] = handler
61
+
65
62
task. resume ( )
66
63
}
67
64
}
@@ -366,6 +363,23 @@ func decode<T: Decodable>(_ data: Data, using decoder: JSONDecoder) async throws
366
363
}
367
364
}
368
365
366
+ /// With iOS 16, there is now a delegate method (`didCreateTask`) that gets
367
+ /// called outside of the session's delegate queue, which means that the access
368
+ /// needs to be synchronized.
369
+ private final class TaskHandlersDictionary {
370
+ private let lock = NSLock ( )
371
+ private var handlers = [ URLSessionTask: TaskHandler] ( )
369
372
370
-
371
-
373
+ subscript( task: URLSessionTask ) -> TaskHandler ? {
374
+ get {
375
+ lock. lock ( )
376
+ defer { lock. unlock ( ) }
377
+ return handlers [ task]
378
+ }
379
+ set {
380
+ lock. lock ( )
381
+ defer { lock. unlock ( ) }
382
+ handlers [ task] = newValue
383
+ }
384
+ }
385
+ }
0 commit comments