SessionDelegate首先声明一点它的类型是一个类,而不是一个协议,第一次看的时候就把它当做成一个协议,它是一个实现URLSessionDataDelegate的类,按源码的注释,它的行为像是一个下载任务的管理器。不过也确实是这样,因为它实现了SessionDataTask的管理
private var tasks: [URL: SessionDataTask] = [:]
又是熟悉添加获取取消等一系列操作给人感觉思路很清晰
SessionDataTask的管理
1.添加SessionDataTask
func append(
_ task: SessionDataTask,
url: URL,
callback: SessionDataTask.TaskCallback) -> DownloadTask
{
let token = task.addCallback(callback)
return DownloadTask(sessionTask: task, cancelToken: token)
}
着这里顺便介绍下DownloadTask结构体
DownloadTask结构体可以理解为对SessionDataTask的二次封装
public struct DownloadTask {
public let sessionTask: SessionDataTask
public let cancelToken: SessionDataTask.CancelToken
public func cancel() {
sessionTask.cancel(token: cancelToken)
}
}
2.获取SessionDataTask
private func task(for task: URLSessionTask) -> SessionDataTask? {
guard let url = task.originalRequest?.url else {
return nil
}
lock.lock()
defer { lock.unlock() }
guard let sessionTask = tasks[url] else {
return nil
}
guard sessionTask.task.taskIdentifier == task.taskIdentifier else {
return nil
}
return sessionTask
}
func task(for url: URL) -> SessionDataTask? {
lock.lock()
defer { lock.unlock() }
return tasks[url]
}
3.获取SessionDataTask
func cancel(url: URL) {
lock.lock()
let task = tasks[url]
lock.unlock()
task?.forceCancel()
}
URLSessionDataDelegate的实现
extension SessionDelegate: URLSessionDataDelegate {
func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive data: Data) {
guard let task = self.task(for: dataTask) else {
return
}
task.didReceiveData(data)
if let expectedContentLength = dataTask.response?.expectedContentLength, expectedContentLength != -1 {
let dataLength = Int64(task.mutableData.count)
DispatchQueue.main.async {
task.callbacks.forEach { callback in
callback.onProgress?.call((dataLength, expectedContentLength))
}
}
}
}
func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) {
guard let sessionTask = self.task(for: task) else { return }
if let url = task.originalRequest?.url {
let result: Result<URLResponse, KingfisherError>
if let error = error {
result = .failure(KingfisherError.responseError(reason: .URLSessionError(error: error)))
} else if let response = task.response {
result = .success(response)
} else {
result = .failure(KingfisherError.responseError(reason: .noURLResponse(task: sessionTask)))
}
onDownloadingFinished.call((url, result))
}
let result: Result<(Data, URLResponse?), KingfisherError>
if let error = error {
result = .failure(KingfisherError.responseError(reason: .URLSessionError(error: error)))
} else {
if let data = onDidDownloadData.call(sessionTask), let finalData = data {
result = .success((finalData, task.response))
} else {
result = .failure(KingfisherError.responseError(reason: .dataModifyingFailed(task: sessionTask)))
}
}
onCompleted(task: task, result: result)
}
可以看出通过实现URLSessionDataDelegate完成了进度回调,下载任务完成时的回调。并在任务完成的时候将task移除。
网友评论