美文网首页
Kingfisher源码之SessionDelegate

Kingfisher源码之SessionDelegate

作者: Mannyao | 来源:发表于2020-08-24 14:59 被阅读0次

    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移除。

    相关文章

      网友评论

          本文标题:Kingfisher源码之SessionDelegate

          本文链接:https://www.haomeiwen.com/subject/jtagjktx.html