美文网首页
Alamofire(三)后台下载原理

Alamofire(三)后台下载原理

作者: 孔雨露 | 来源:发表于2019-08-24 23:41 被阅读0次

    @TOC

    • 前面两篇博客:alamofire(一)网络基础alamofire(二) URLSession 分别讲解了alamofire框架实现所需的一些必备的网络基础知识和iOS 系统网络框架Api。属性这些知识后,我们再来探索alamofire框架的设计思想和底层实现就事半功倍了。本篇博客主要讲解Alamofire的一个重要功能“后台下载”的实现原理。
    • 我们先来回顾一下alamofire(一)网络基础这篇博客留下的一个彩蛋:
    alamofire框架简介

    从这个结构图里面我们可以大致了解一下Alamofire框架主要涉及哪些方面的知识。总的来说alamofire是一个非常牛逼的网络框架,它是AFNetwork的父亲开发的,在github上面有3万多个星星,足以证明他是多么的牛B。非常值得我们深入研究。

    URLSession后台下载

    • 在上一篇博客 alamofire(二) URLSession 已经大致的讲解了一些URLSession后台下载的流程和实现代码。这里再来回顾总结一下,有利于更好的理解Alamofire框架后台下载的原理。

    URLSession后台流程

    URLSession实现后台下载的步骤如下图:

    URLSession实现后台下载的步骤

    如上图6步就可以实现后台下载,其实代码实现起来也很简单。

    • 上图的1-3步可以由于代码比较简单可以合在一起讲,具体就是:首先初始化一个 background 的模式的 configuration。configuration有 三种模式 ,只有background 的模式才能进行后台下载。
      然后,通过configuration初始化网络下载会话 session,设置相关代理,回调数据信号响应。
      最后,session创建downloadTask任务-resume启动 (默认状态:suspend),具体代码如下:
    // 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启动
    let url = URL(string: "https://dldir1.qq.com/qqfile/QQforMac/QQ_V6.5.5.dmg")!
    session.downloadTask(with: url).resume()
    
    • 接下来就是第4步,设置代理。依赖苹果封装的网络处理API,发起连接 - 发送相关请求 - 回调代理响应
      这里只需要实现两个回调就可以了
    //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")
        }
    }
    
    • 接着下需要处理第5步中的backgroundSessionCompletionHandler回调。定义一个全局变量用于保存后台下载的completionHandler
    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保存相应的回调,这也是非常必要的!告诉系统后台下载回来及时刷新屏幕

    • 最后第6步:在urlSessionDidFinishEvents的代理实现调用。代码如下:
    func urlSessionDidFinishEvents(forBackgroundURLSession session: URLSession) {
        print("后台任务下载回来")
        //因为涉及到UI刷新,需要确保在主线程中进行
        //如果不执行下面代码,会导致刚进入前台时页面卡顿,影响用户体验,同时还会打印警告信息。
        DispatchQueue.main.async {
            guard let appDelegate = UIApplication.shared.delegate as? AppDelegate, let backgroundHandle = appDelegate.backgroundSessionCompletionHandler else { return }
            backgroundHandle()
        }
    }
    

    注意:如果不实现第6步这个代理里面的回调函数的执行,系统会打印警告信息:`Warning: Application delegate received call to -
    application:handleEventsForBackgroundURLSession:completionHandler:
    but the completion handler was never called.
    虽然这样还是可以实现后台下载,但是会导致总在IOS系统总在后台刷新,导致性能浪费,出现页面卡顿,影响用户体验。

    • 完成如上6个步骤就可以实现后台下载功能.保存handleEventsForBackgroundURLSession方法的completionHandler回调,这是非常重要的。告诉系统后台下载回来及时刷新屏幕.
    • 在切到后台之后,URLSessionDownloadDelegate 的代理方法不会再收到 Task 相关的消息。当所有 Task 全都完成后,系统才会调用 AppDelegate 的application:handleEventsForBackgroundURLSession:completionHandler:回调。

    Alamofire后台下载

    在讲解Alamofire后台下载前,有必要先熟悉一下Alamofire下载需要使用的几个关键类。

    SessionManager

    参考:大神Cooci博客:https://juejin.im/post/5d57ff89f265da03913512df

    相关文章

      网友评论

          本文标题:Alamofire(三)后台下载原理

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