美文网首页
Kingfisher源码之ImageDownLoader

Kingfisher源码之ImageDownLoader

作者: Mannyao | 来源:发表于2020-08-25 09:10 被阅读0次

    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)
        }
    }
    

    相关文章

      网友评论

          本文标题:Kingfisher源码之ImageDownLoader

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