Kingfisher源码之ImageDownLoader
2020-08-25 本文已影响0人
Mannyao
ImageDownloader请求图片url下载管理
先看初始化方法:
public init(name: String) {
if name.isEmpty {
fatalError("must have a name")
}
self.name = name
sessionDelegate = SessionDelegate()
session = URLSession(configuration: sessionConfiguration, delegate: sessionDelegate, delegateQueue: nil)
authenticationChallengeResponder = self
setupSessionHandler()
}
1.初始化一个SessionDelegate
2.初始化一个URLSession
ImageDownloader中有自己的delegate,ImageDownloaderDelegte提供下载的回调
public protocol ImageDownloaderDelegte: AnyObject {
func imageDownloader(_ downloader: ImageDownloader, willDownloadImageForURL url: URL, with request: URLRequest?)
func imageDownloader(_ downloader: ImageDownloader, didFinishDownloadingImageForURL url: URL, with response: URLResponse?, error: Error?)
func imageDownloader(_ downloader: ImageDownloader, didDownload data: Data, for url: URL) -> Data?
func imageDownloader(_ downloader: ImageDownloader, didDownload image: Image, for url: URL, with response: URLResponse?)
func isValidStatusCode(_ code: Int, for downloader: ImageDownloader) -> Bool
}
重点看图片下载的过程
下载步骤解析
1.创建URLRequest
2.对request的修改
3.将参数中的progressBlock和completionHandler分别转为TaskCallback中的onprogress和onCompleted
4.创建TaskCallback
5.创建sessionDataTask
6.转接sessionTask完成的回调到ImageDownloaderDelegte
7.启动sessionTask
@discardableResult
func downloadImage(with url: URL,
options: KingfisherParedOptionsInfo,
progressBlock: DownloadProgressBlock? = nil,
completionHandler: ((Result<ImageLoadingResult, KingfisherError>) -> Void)? = nil) -> DownloadTask? {
//1.创建URLRequest
var request = URLRequest(url: url, cachePolicy: .reloadIgnoringLocalCacheData, timeoutInterval: downloadTimeout)
request.httpShouldUsePipelining = requestUserPipelining
//2.对request的修改
if let requestModifier = options.requestModifier {
guard let r = requestModifier.modified(for: request) else {
options.callbackQueue.exectue {
completionHandler?(.failure(KingfisherError.requestError(reason: .emptyRequest)))
}
return nil
}
request = r
}
guard let url = request.url, !url.absoluteString.isEmpty else {
options.callbackQueue.exectue {
completionHandler?(.failure(KingfisherError.requestError(reason: .emptyRequest)))
}
return nil
}
//3.将参数中的progressBlock和completionHandler分别转为TaskCallback中的onprogress和onCompleted
let onProgress = progressBlock.map {
block -> Delegate<(Int64, Int64), Void> in
let delegate = Delegate<(Int64, Int64), Void>()
delegate.delegate(on: self) { (_, progress) in
let (downloaded, total) = progress
block(downloaded, total)
}
return delegate
}
let onCompleted = completionHandler.map {
block -> Delegate<Result<ImageLoadingResult, KingfisherError>, Void> in
let delegate = Delegate<Result<ImageLoadingResult, KingfisherError>, Void>()
delegate.delegate(on: self) { (_, result) in
block(result)
}
return delegate
}
//4.创建TaskCallback
let callback = SessionDataTask.TaskCallback(onprogress: onProgress, onCompleted: onCompleted, options: options)
let downloadTask: DownloadTask
//5.创建sessionDataTask
if let existingTask = sessionDelegate.task(for: url) {
downloadTask = sessionDelegate.append(existingTask, url: url, callback: callback)
} else {
let sessionDataTask = session.dataTask(with: request)
sessionDataTask.priority = options.downloadPriority
downloadTask = sessionDelegate.add(sessionDataTask, url: url, callback: callback)
}
let sessionTask = downloadTask.sessionTask
if !sessionTask.started {
//6.转接sessionTask完成的回调到ImageDownloaderDelegte
sessionTask.onTaskDone.delegate(on: self) { (self, done) in
let (result, callbacks) = done
do {
let value = try result.get()
self.delegate?.imageDownloader(self, didFinishDownloadingImageForURL: url, with: value.1, error: nil)
} catch {
self.delegate?.imageDownloader(self, didFinishDownloadingImageForURL: url, with: nil, error: error)
}
switch result {
case .success(let (data, response)):
let processor = ImageDataProcessor(data: data, callbacks: callbacks, processingQueue: options.processingQueue)
processor.onImageProcessed.delegate(on: self) { (self, result) in
let (result, callback) = result
if let image = try? result.get() {
self.delegate?.imageDownloader(self, didDownload: image, for: url, with: response)
}
let imageResult = result.map { ImageLoadingResult(image: $0, url: url, originalData: data) }
let queue = callback.options.callbackQueue
queue.exectue {
callback.onCompleted?.call(imageResult)
}
}
processor.process()
case .failure(let error):
callbacks.forEach { callback in
let queue = callback.options.callbackQueue
queue.exectue {
callback.onCompleted?.call(.failure(error))
}
}
}
}
//7.启动sessionTask
sessionTask.resume()
}
return downloadTask
}
下载方法有两个闭包,一个返回进度,一个返回结果
取消Task
通过自己的属性sessionDelegate类取消
//MARK: Cancelling Task
extension ImageDownloader {
public func cancelAll() {
sessionDelegate.cancelAll()
}
public func cancel(url: URL) {
sessionDelegate.cancel(url: url)
}
}