美文网首页
Alamofire-下载器

Alamofire-下载器

作者: Code_人生 | 来源:发表于2019-08-29 14:31 被阅读0次

一、suspend和resume

  • Requestsuspend
    /// Suspends the request.
    open func suspend() {
        guard let task = task else { return }

        task.suspend()

        NotificationCenter.default.post(
            name: Notification.Name.Task.DidSuspend,
            object: self,
            userInfo: [Notification.Key.Task: task]
        )
    }
  • Requestresume
    /// Resumes the request.
    open func resume() {
        guard let task = task else { delegate.queue.isSuspended = false ; return }

        if startTime == nil { startTime = CFAbsoluteTimeGetCurrent() }

        task.resume()

        NotificationCenter.default.post(
            name: Notification.Name.Task.DidResume,
            object: self,
            userInfo: [Notification.Key.Task: task]
        )
    }
  • 总结 resume之后可以suspend,suspend之后也可以resume
        currentDownloadRequest = LGDowloadManager.shared.manager.download(url) { [weak self](url, reponse) -> (destinationURL: URL, options: DownloadRequest.DownloadOptions) in
            let fileUrl = self?.filePath.appendingPathComponent(reponse.suggestedFilename!)
            return (fileUrl!,[.removePreviousFile, .createIntermediateDirectories] )
        }

二、cancel

  • Requestcancel
    /// Cancels the request.
    open func cancel() {
        guard let task = task else { return }

        task.cancel()

        NotificationCenter.default.post(
            name: Notification.Name.Task.DidCancel,
            object: self,
            userInfo: [Notification.Key.Task: task]
        )
    }
  • DownloadRequestcancel,重写了RequestcancelAlamofire帮我们保存了self.downloadDelegate.resumeData
    /// Cancels the request.
    open override func cancel() {
        downloadDelegate.downloadTask.cancel { self.downloadDelegate.resumeData = $0 }

        NotificationCenter.default.post(
            name: Notification.Name.Task.DidCancel,
            object: self,
            userInfo: [Notification.Key.Task: task as Any]
        )
    }
  • 总结Alamofire帮我们保存了resumeData,直接取出来用,避免了在沙盒中找到然后在后面拼接,resumeData中包含了这些信息哦
  • 优化代码二
        if let resumeData = LGDowloadManager.shared.currentDownloadRequest?.resumeData {
            currentDownloadRequest = LGDowloadManager.shared.manager.download(resumingWith: resumeData)
        }else{
            currentDownloadRequest = LGDowloadManager.shared.manager.download(url) { [weak self](url, reponse) -> (destinationURL: URL, options: DownloadRequest.DownloadOptions) in
                let fileUrl = self?.filePath.appendingPathComponent(reponse.suggestedFilename!)
                return (fileUrl!,[.removePreviousFile, .createIntermediateDirectories] )
            }
        }

三、用户杀死应用程序

  • 用户杀死应用程序,会导致下载暂停,再次启动程序会来到urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?)
extension SessionDelegate: URLSessionTaskDelegate {
// 省略...
    open func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) {
        /// Executed after it is determined that the request is not going to be retried
        let completeTask: (URLSession, URLSessionTask, Error?) -> Void = { [weak self] session, task, error in
            guard let strongSelf = self else { return }

            strongSelf.taskDidComplete?(session, task, error)
            // 省略...
        }
    }
}
  • Alamofire对外闭包的使用,对外实现taskDidComplete闭包,就可以监控到啦
  • 取出error中的NSURLSessionDownloadTaskResumeData,赋值给LGDowloadManager.shared.resumeData
  • 优化代码三
        manager.delegate.taskDidComplete = { (seesion,task, error) in
            if let error = error {
                print("taskDidComplete的error情况: \(error)")
                if let resumeData = (error as NSError).userInfo[NSURLSessionDownloadTaskResumeData] as? Data {
                    // resumeData 存储
                    LGDowloadManager.shared.resumeData = resumeData
                    print("来了")
                }
            }else{
                print("taskDidComplete的task情况: \(task)")
            }
        }
        if self.resumeData != nil {
            currentDownloadRequest = LGDowloadManager.shared.manager.download(resumingWith: self.resumeData!)
        }else{
            if let resumeData = LGDowloadManager.shared.currentDownloadRequest?.resumeData {
                currentDownloadRequest = LGDowloadManager.shared.manager.download(resumingWith: resumeData)
            }else{
                currentDownloadRequest = LGDowloadManager.shared.manager.download(url) { [weak self](url, reponse) -> (destinationURL: URL, options: DownloadRequest.DownloadOptions) in
                    let fileUrl = self?.filePath.appendingPathComponent(reponse.suggestedFilename!)
                    return (fileUrl!,[.removePreviousFile, .createIntermediateDirectories] )
                }
            }
        }

四、代码崩溃导致kill程序

  • 后台其实还是在继续下载的
  • 进度返回 实现闭包downloadTaskDidWriteData
  • 不能再继续点击开始
        manager.session.getTasksWithCompletionHandler({ (dataTasks, uploadTask, downloadTasks) in
            print("回调监控: \(downloadTasks)")
        })

        manager.delegate.downloadTaskDidFinishDownloadingToURL = { (session, downloadTask, url) in

            guard let response = downloadTask.response as? HTTPURLResponse else {return}

            let fileUrl = LGDowloadManager.shared.filePath.appendingPathComponent(response.suggestedFilename!)

            do {
                if FileManager.default.fileExists(atPath: fileUrl.path) {
                    try FileManager.default.removeItem(at: fileUrl)
                }
                let directory = fileUrl.deletingLastPathComponent()
                try FileManager.default.createDirectory(at: directory, withIntermediateDirectories: true)

                try FileManager.default.moveItem(at: url, to: fileUrl)
                print("文件移动成功")
            } catch {
                print("文件移动出错了 \(error)")
            }
        }

五、代码实例

import UIKit
import Alamofire

class LGDowloadManager: NSObject {
    static let shared = LGDowloadManager()
    var currentDownloadRequest: DownloadRequest?
    var resumeData: Data?
    var downloadTasks: Array<URLSessionDownloadTask>?
    var filePath: URL{
        return FileManager.default.urls(for: .documentDirectory, in: FileManager.SearchPathDomainMask.userDomainMask).first!.appendingPathComponent("com.lgcooci.download.cn")
    }
    
    //MARK: - 单利方便获取
    let manager: SessionManager = {
        let configuration = URLSessionConfiguration.background(withIdentifier: "com.lgcooci.AlamofireDowload")
        configuration.httpAdditionalHeaders = SessionManager.defaultHTTPHeaders
        configuration.sharedContainerIdentifier = "group.com.lgcooci.AlamofireDowload"
        let manager = SessionManager(configuration: configuration)
        manager.startRequestsImmediately = true
        manager.backgroundCompletionHandler = {
            debugPrint("后台完成回来了")
        }
        // 用户kill 进来
        manager.delegate.taskDidComplete = { (seesion,task, error) in
            if let error = error {
                print("taskDidComplete的error情况: \(error)")
                if let resumeData = (error as NSError).userInfo[NSURLSessionDownloadTaskResumeData] as? Data {
                    // resumeData 存储
                    LGDowloadManager.shared.resumeData = resumeData
                    print("来了")
                }
            }else{
                print("taskDidComplete的task情况: \(task)")
            }
        }
        
        manager.session.getTasksWithCompletionHandler({ (dataTasks, uploadTask, downloadTasks) in
            print("回调监控: \(downloadTasks)")
        })
        
        manager.delegate.downloadTaskDidFinishDownloadingToURL = { (session, downloadTask, url) in

            guard let response = downloadTask.response as? HTTPURLResponse else {return}
        
            let fileUrl = LGDowloadManager.shared.filePath.appendingPathComponent(response.suggestedFilename!)
            
            do {
                if FileManager.default.fileExists(atPath: fileUrl.path) {
                    try FileManager.default.removeItem(at: fileUrl)
                }
                let directory = fileUrl.deletingLastPathComponent()
                try FileManager.default.createDirectory(at: directory, withIntermediateDirectories: true)

                try FileManager.default.moveItem(at: url, to: fileUrl)
                print("文件移动成功")
            } catch {
                print("文件移动出错了 \(error)")
            }
        }
        
        return manager
    }()
    
    //MARK: - 下载封装入口 - 断点续传
    func lgDowload(_ url: URLConvertible) -> DownloadRequest {
        
        if self.resumeData != nil {
            currentDownloadRequest = LGDowloadManager.shared.manager.download(resumingWith: self.resumeData!)
        }else{
            if let resumeData = LGDowloadManager.shared.currentDownloadRequest?.resumeData {
                currentDownloadRequest = LGDowloadManager.shared.manager.download(resumingWith: resumeData)
            }else{
                currentDownloadRequest = LGDowloadManager.shared.manager.download(url) { [weak self](url, reponse) -> (destinationURL: URL, options: DownloadRequest.DownloadOptions) in
                    let fileUrl = self?.filePath.appendingPathComponent(reponse.suggestedFilename!)
                    return (fileUrl!,[.removePreviousFile, .createIntermediateDirectories] )
                }
            }
        }
        return currentDownloadRequest!
    }
    
    //MARK: - 暂停/继续/取消
    func suspend() {
        self.currentDownloadRequest?.suspend()
    }
    
    func resume() {
        self.currentDownloadRequest?.resume()
    }
    
    func cancel() {
        self.currentDownloadRequest?.cancel()
    }
    
    func clear() {
        let filePath = NSHomeDirectory()+"/Documents/com.lgcooci.download.cn"
        if FileManager.default.fileExists(atPath: filePath) {
            try! FileManager.default.removeItem(at: self.filePath)
            print("清理完成")
        }
    }
}

相关文章

  • Alamofire-下载器

    一、suspend和resume Request的suspend Request的resume 总结 resume...

  • Alamofire - Request

    上一篇 Alamofire-后台下载 其中就介绍了关于 SesssionManager 到 SessionDele...

  • 2019-08-22

    Alamofire-初探

  • Alamofire-后台下载

    系统后台下载 config三种模式defaultephemeral本文主角background 使用分片下载 官方...

  • Alamofire-后台下载

    这一篇主要讲解后台下载,后台下载对于应用程序来说,是一个非常重要也比较好用的功能。虽然用好后台下载的确能够大大提升...

  • Alamofire-后台下载

    上一篇文章提到了后台下载,下面看看在Alamofire中是如何处理后台下载的。首先使用原生写法来实现一个后台下载任...

  • Alamofire-后台下载

    1、枚举 HTTPMethod rawValue属性值关联 2、单例 SessionManager.default...

  • Alamofire-后台下载问题

    问题一 -999 被释放了,会报-999,所以可以确定URLSession.init是一个单例 问题二 掉帧 测试...

  • Alamofire框架使用

    Alamofire-使用[https://blog.csdn.net/yahibo/article/details...

  • Alamofire-多表单上传

    一、AFN上传文件 二、Alamofire-多表单上传 点击.upload multipartFormData(f...

网友评论

      本文标题:Alamofire-下载器

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