@@ -22,7 +22,12 @@ final class ResourceLoaderDelegate: NSObject, AVAssetResourceLoaderDelegate, URL
22
22
private lazy var fileHandle = MediaFileHandle ( filePath: saveFilePath)
23
23
24
24
private var session : URLSession ?
25
- private let queue = DispatchQueue ( label: " com.gcd.CachingPlayerItemQueue " , qos: . userInitiated)
25
+ private let operationQueue = {
26
+ let queue = OperationQueue ( )
27
+ queue. name = " CachingPlayerItemOperationQueue "
28
+ queue. maxConcurrentOperationCount = 1
29
+ return queue
30
+ } ( )
26
31
private var pendingContentInfoRequest : PendingContentInfoRequest ? {
27
32
didSet { oldValue? . cancelTask ( ) }
28
33
}
@@ -42,14 +47,9 @@ final class ResourceLoaderDelegate: NSObject, AVAssetResourceLoaderDelegate, URL
42
47
self . saveFilePath = saveFilePath
43
48
self . owner = owner
44
49
super. init ( )
45
-
46
50
NotificationCenter . default. addObserver ( self , selector: #selector( handleAppWillTerminate) , name: UIApplication . willTerminateNotification, object: nil )
47
51
}
48
52
49
- deinit {
50
- invalidateAndCancelSession ( shouldResetData: false )
51
- }
52
-
53
53
// MARK: AVAssetResourceLoaderDelegate
54
54
55
55
func resourceLoader( _ resourceLoader: AVAssetResourceLoader , shouldWaitForLoadingOfRequestedResource loadingRequest: AVAssetResourceLoadingRequest ) -> Bool {
@@ -68,15 +68,15 @@ final class ResourceLoaderDelegate: NSObject, AVAssetResourceLoaderDelegate, URL
68
68
let request = PendingDataRequest ( url: url, session: session, loadingRequest: loadingRequest, customHeaders: owner? . urlRequestHeaders)
69
69
request. delegate = self
70
70
request. startTask ( )
71
- pendingDataRequests [ request. id] = request
71
+ addOperationOnQueue { [ weak self ] in self ? . pendingDataRequests [ request. id] = request }
72
72
return true
73
73
} else {
74
74
return false
75
75
}
76
76
}
77
77
78
78
func resourceLoader( _ resourceLoader: AVAssetResourceLoader , didCancel loadingRequest: AVAssetResourceLoadingRequest ) {
79
- queue . async { [ weak self] in
79
+ addOperationOnQueue { [ weak self] in
80
80
guard let self else { return }
81
81
guard let key = pendingDataRequests. first ( where: { $1. loadingRequest. request. url == loadingRequest. request. url } ) ? . key else { return }
82
82
@@ -88,7 +88,7 @@ final class ResourceLoaderDelegate: NSObject, AVAssetResourceLoaderDelegate, URL
88
88
// MARK: URLSessionDelegate
89
89
90
90
func urlSession( _ session: URLSession , dataTask: URLSessionDataTask , didReceive data: Data ) {
91
- queue . async { [ weak self] in
91
+ addOperationOnQueue { [ weak self] in
92
92
guard let self else { return }
93
93
94
94
pendingDataRequests [ dataTask. taskIdentifier] ? . respond ( withRemoteData: data)
@@ -98,7 +98,7 @@ final class ResourceLoaderDelegate: NSObject, AVAssetResourceLoaderDelegate, URL
98
98
bufferData. append ( data)
99
99
writeBufferDataToFileIfNeeded ( )
100
100
101
- guard let response = contentInfoResponse else { return }
101
+ guard let response = contentInfoResponse ?? dataTask . response else { return }
102
102
103
103
DispatchQueue . main. async {
104
104
self . owner? . delegate? . playerItem ? ( self . owner!,
@@ -109,12 +109,13 @@ final class ResourceLoaderDelegate: NSObject, AVAssetResourceLoaderDelegate, URL
109
109
}
110
110
111
111
func urlSession( _ session: URLSession , task: URLSessionTask , didCompleteWithError error: Error ? ) {
112
- queue . async { [ weak self] in
112
+ addOperationOnQueue { [ weak self] in
113
113
guard let self else { return }
114
114
115
115
let taskId = task. taskIdentifier
116
+ if let error {
117
+ guard ( error as? URLError ) ? . code != . cancelled else { return }
116
118
117
- if let error = error {
118
119
if pendingContentInfoRequest? . id == taskId {
119
120
finishLoadingPendingRequest ( withId: taskId, error: error)
120
121
downloadFailed ( with: error)
@@ -141,7 +142,7 @@ final class ResourceLoaderDelegate: NSObject, AVAssetResourceLoaderDelegate, URL
141
142
writeBufferDataToFileIfNeeded ( forced: true )
142
143
}
143
144
144
- let error = verifyResponse ( )
145
+ let error = verify ( response : contentInfoResponse ?? task . response )
145
146
146
147
guard error == nil else {
147
148
downloadFailed ( with: error!)
@@ -169,10 +170,11 @@ final class ResourceLoaderDelegate: NSObject, AVAssetResourceLoaderDelegate, URL
169
170
func invalidateAndCancelSession( shouldResetData: Bool = true ) {
170
171
session? . invalidateAndCancel ( )
171
172
session = nil
173
+ operationQueue. cancelAllOperations ( )
172
174
173
175
if shouldResetData {
174
176
bufferData = Data ( )
175
- queue . async { [ weak self] in
177
+ addOperationOnQueue { [ weak self] in
176
178
guard let self else { return }
177
179
178
180
pendingContentInfoRequest = nil
@@ -228,8 +230,8 @@ final class ResourceLoaderDelegate: NSObject, AVAssetResourceLoaderDelegate, URL
228
230
}
229
231
}
230
232
231
- private func verifyResponse ( ) -> NSError ? {
232
- guard let response = contentInfoResponse as? HTTPURLResponse else { return nil }
233
+ private func verify ( response : URLResponse ? ) -> NSError ? {
234
+ guard let response = response as? HTTPURLResponse else { return nil }
233
235
234
236
let shouldVerifyDownloadedFileSize = CachingPlayerItemConfiguration . shouldVerifyDownloadedFileSize
235
237
let minimumExpectedFileSize = CachingPlayerItemConfiguration . minimumExpectedFileSize
@@ -254,6 +256,16 @@ final class ResourceLoaderDelegate: NSObject, AVAssetResourceLoaderDelegate, URL
254
256
}
255
257
}
256
258
259
+ private func addOperationOnQueue( _ block: @escaping ( ) -> Void ) {
260
+ let blockOperation = BlockOperation ( )
261
+ blockOperation. addExecutionBlock ( { [ unowned blockOperation] in
262
+ guard blockOperation. isCancelled == false else { return }
263
+
264
+ block ( )
265
+ } )
266
+ operationQueue. addOperation ( blockOperation)
267
+ }
268
+
257
269
@objc private func handleAppWillTerminate( ) {
258
270
invalidateAndCancelSession ( shouldResetData: false )
259
271
}
@@ -265,12 +277,12 @@ extension ResourceLoaderDelegate: PendingDataRequestDelegate {
265
277
func pendingDataRequest( _ request: PendingDataRequest , hasSufficientCachedDataFor offset: Int , with length: Int ) -> Bool {
266
278
fileHandle. fileSize >= length + offset
267
279
}
268
-
280
+
269
281
func pendingDataRequest( _ request: PendingDataRequest ,
270
282
requestCachedDataFor offset: Int ,
271
283
with length: Int ,
272
284
completion: @escaping ( ( _ continueRequesting: Bool ) -> Void ) ) {
273
- queue . async { [ weak self] in
285
+ addOperationOnQueue { [ weak self] in
274
286
guard let self else { return }
275
287
276
288
let bytesCached = fileHandle. fileSize
0 commit comments