B48811000e79b8da087de844949ad59d
Alamofire(2)— 后台下载

😊😊😊Alamofire专题目录,欢迎及时反馈交流 😊😊😊


Alamofire 目录直通车 --- 和谐学习,不急不躁!


这一篇主要讲解后台下载,后台下载对于应用程序来说,是一个非常重要也比较好用的功能。虽然用好后台下载的确能够大大提升用户体验,但是又很多时候我们也会遇到很多坑点以及疑惑点。其中会通过 URLSessionAlamofire 两种形式分别展开讨论,对比学习才能更能体会 Alamofire 的设计思维。Alamofire持续更新中,希望大家希望!

一、URLSession处理后台下载

URLSession在后台处理方面还是比较简单的。

// 1:初始化一个background的模式的configuration
let configuration = URLSessionConfiguration.background(withIdentifier: self.createID())
// 2:通过configuration初始化网络下载会话
let session = URLSession.init(configuration: configuration, delegate: self, delegateQueue: OperationQueue.main)
// 3:session创建downloadTask任务-resume启动
session.downloadTask(with: url).resume()
  • 初始化一个 background 的模式的 configurationconfiguration 三种模式 ,只有background 的模式才能进行后台下载。
  • 通过configuration初始化网络下载会话 session,设置相关代理,回调数据信号响应。
  • session创建downloadTask任务-resume启动 (默认状态:suspend)
  • 接下来依赖苹果封装的网络处理,发起连接 - 发送相关请求 - 回调代理响应
//MARK: - session代理
extension ViewController:URLSessionDownloadDelegate{
    func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didFinishDownloadingTo location: URL) {
        // 下载完成 - 开始沙盒迁移
        print("下载完成 - \(location)")
        let locationPath = location.path
        //拷贝到用户目录(文件名以时间戳命名)
        let documnets = NSHomeDirectory() + "/Documents/" + self.lgCurrentDataTurnString() + ".mp4"
        print("移动地址:\(documnets)")
        //创建文件管理器
        let fileManager = FileManager.default
        try! fileManager.moveItem(atPath: locationPath, toPath: documnets)
    }

    func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didWriteData bytesWritten: Int64, totalBytesWritten: Int64, totalBytesExpectedToWrite: Int64) {
        print(" bytesWritten \(bytesWritten)\n totalBytesWritten \(totalBytesWritten)\n totalBytesExpectedToWrite \(totalBytesExpectedToWrite)")
        print("下载进度: \(Double(totalBytesWritten)/Double(totalBytesExpectedToWrite))\n")
    }
}
  • 实现了 URLSessionDownloadDelegatedidFinishDownloadingTo代理,实现下载完成转移临时文件里的数据到相应沙盒保存
  • 通过urlSession(_ session: downloadTask:didWriteData bytesWritten: totalBytesWritten: totalBytesExpectedToWrite: ) 的代理监听下载进度
  • 这里也是因为 http的分片传输 才导致的进度有段的感觉,其实证明内部也是对这个代理方法不断调用,才能进度回调!

这里实现了下载功能,但是对于我们需要的后台下载还差一段

Applications using an NSURLSession with a background configuration may be launched or resumed in the background in order to handle the completion of tasks in that session, or to handle authentication. This method will be called with the identifier of the session needing attention. Once a session has been created from a configuration object with that identifier, the session's delegate will begin receiving callbacks. If such a session has already been created (if the app is being resumed, for instance), then the delegate will start receiving callbacks without any action by the application. You should call the completionHandler as soon as you're finished handling the callbacks.

苹果爸爸总是能在合适时间给你优秀的建议,阅读文档的能力决定你是否能够在这个时代站稳自己的脚尖

class AppDelegate: UIResponder, UIApplicationDelegate {
    var window: UIWindow?
    //用于保存后台下载的completionHandler
    var backgroundSessionCompletionHandler: (() -> Void)?
    func application(_ application: UIApplication, handleEventsForBackgroundURLSession identifier: String, completionHandler: @escaping () -> Void) {
        self.backgroundSessionCompletionHandler = completionHandler
    }
}
  • 实现handleEventsForBackgroundURLSession就可以完美后台下载
  • 告诉代理与 URLSession 相关的事件正在等待处理。
  • 应用程序在所有与 URLSession对象 关联的后台传输完成后调用此方法,无论传输成功完成还是导致错误。如果一个或多个传输需要认证,应用程序也会调用这个方法。
  • 使用此方法可以重新连接任何 URLSession 并更新应用程序的用户界面。例如,您可以使用此方法更新进度指示器或将新内容合并到视图中。在处理事件之后,在 completionHandler 参数中执行 block,这样应用程序就可以获取用户界面的刷新。
  • 我们通过handleEventsForBackgroundURLSession保存相应的回调,这也是非常必要的!告诉系统后台下载回来及时刷新屏幕

urlSessionDidFinishEvents的代理实现调用

func urlSessionDidFinishEvents(forBackgroundURLSession session: URLSession) {
    print("后台任务下载回来")
    DispatchQueue.main.async {
        guard let appDelegate = UIApplication.shared.delegate as? AppDelegate, let backgroundHandle = appDelegate.backgroundSessionCompletionHandler else { return }
        backgroundHandle()
    }
}
  • 拿到UIApplication.shared.delegate的回调函数执行
  • 注意线程切换主线程,毕竟刷新界面

那么如果不实现这个代理里面的回调函数的执行,那么会发生什么呢

  • 后台下载的能力是不会影响的
  • 但是会爆出非常验证界面刷新卡顿,影响用户体验
  • 同时打印台会爆出警告
Warning: Application delegate received call to -
application:handleEventsForBackgroundURLSession:completionHandler: 
but the completion handler was never called.
top Created with Sketch.