美文网首页
Alamofire实现后台下载

Alamofire实现后台下载

作者: H_Zimi | 来源:发表于2019-08-18 21:28 被阅读0次

咔咔咔,敲完一个Alamofire的下载实现:

func downLoadFile() {
    SessionManager.default.download(urlString) { (url, response) -> (destinationURL: URL, options: DownloadRequest.DownloadOptions) in
        let docUrl = FileManager.default.urls(for: FileManager.SearchPathDirectory.documentDirectory, in: FileManager.SearchPathDomainMask.userDomainMask).first
        let fileUrl = docUrl?.appendingPathComponent(response.suggestedFilename!)
        return (fileUrl!, [.removePreviousFile, .createIntermediateDirectories])
        }.downloadProgress { (progress) in
            print("\(progress)")
        }.response { (respond) in
            print("\(respond)")
    }
}

切到后台时,下载不继续执行,切回后,下载继续执行,后台下载的目的没有达到啊。。。
一通常规操作,目的没有达到啊,为什么?肯定哪里忽略了,default有木有很刺眼?看下呗

public static let `default`: SessionManager = {
    let configuration = URLSessionConfiguration.default
    configuration.httpAdditionalHeaders = SessionManager.defaultHTTPHeaders
    
    return SessionManager(configuration: configuration)
}()
  • SessionManager的一个单例
  • URLSessionConfigurationdefault模式
  • 后台下载需要的模式是background

再看下SessionManagerinit方法

public init(
    configuration: URLSessionConfiguration = URLSessionConfiguration.default,
    delegate: SessionDelegate = SessionDelegate(),
    serverTrustPolicyManager: ServerTrustPolicyManager? = nil)
{
    self.delegate = delegate
    self.session = URLSession(configuration: configuration, delegate: delegate, delegateQueue: nil)

    commonInit(serverTrustPolicyManager: serverTrustPolicyManager)
}
  • 第一个参数configuration的默认值还是URLSessionConfigurationdefualt模式

这个时候我们就需要重新配置为background模式了:

func downLoadBackground() {
    let configuration = URLSessionConfiguration.background(withIdentifier: "com.zimi")
    let backgroundManager = SessionManager(configuration: configuration)
    backgroundManager.download(urlDownloadStr) { (url, response) -> (destinationURL: URL, options: DownloadRequest.DownloadOptions) in
        let documentUrl = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first
        
        let fileUrl = documentUrl?.appendingPathComponent(response.suggestedFilename!)
        
        return (fileUrl!, [.createIntermediateDirectories, .removePreviousFile])
    }
        .response { (response) in
            print("\(response)")
        }.downloadProgress { (progress) in
            print("\(progress.fractionCompleted)")
    }
}
// 控制台打印:<1> load failed with error Error Domain=NSURLErrorDomain Code=-999 "cancelled"

居然报错了。。。
原来是SessionManagerdownLoadBackground方法中是局部变量,进入后台下载时被释放了
改成这样
let backgroundManager: SessionManager = {
    let configuration = URLSessionConfiguration.background(withIdentifier: "com.zimi")
    let sessionManager = SessionManager(configuration: configuration)
    
    return sessionManager
}()

URLSession的官方文档关于后台下载有四步,在Swift - 网络 URLSession中有介绍,当然不能忘了这个重要的步骤了:

func application(_ application: UIApplication, handleEventsForBackgroundURLSession identifier: String, completionHandler: @escaping () -> Void) {
    BackgroundDLViewModel().backgroundManager.backgroundCompletionHandler = completionHandler
}

不然在控制台会打印一个警告,切回的时候也会出下卡顿

Warning: Application delegate received call to -application:handleEventsForBackgroundURLSession:completionHandler: 
but the completion handler was never called.

那么重点来了,在用URLSession来处理后台下载的时候,需要通过urlSessionDidFinishEvents(forBackgroundURLSession session: URLSession)代理方法来执行completionHandler的回调,那么,既然SessionManager的属性backgroundCompletionHandler帮我们保存了completionHandler这个闭包,它是怎么帮我们来调用的呢?
在前面贴出的init方法中有commonInit这个方法的调用,那么我们来看下:

private func commonInit(serverTrustPolicyManager: ServerTrustPolicyManager?) {
    session.serverTrustPolicyManager = serverTrustPolicyManager

    delegate.sessionManager = self

    delegate.sessionDidFinishEventsForBackgroundURLSession = { [weak self] session in
        guard let strongSelf = self else { return }
        DispatchQueue.main.async { strongSelf.backgroundCompletionHandler?() }
    }
}
  • sessionDidFinishEventsForBackgroundURLSession代理的闭包声明里,做了backgroundCompletionHandler闭包回到主线程异步的回调
  • Alamofire中有一个专职delegate的类SessionDelegate,对URLSession的代理方法urlSessionDidFinishEvents(forBackgroundURLSession session: URLSession)进行了实现
open func urlSessionDidFinishEvents(forBackgroundURLSession session: URLSession) {
    sessionDidFinishEventsForBackgroundURLSession?(session)
}
  • SessionDelegate重写了NSObjectresponds方法,通过sessionDidFinishEventsForBackgroundURLSession闭包是否为空来判断是否执行urlSessionDidFinishEvents(forBackgroundURLSession session: URLSession)方法
open override func responds(to selector: Selector) -> Bool {
    #if !os(macOS)
        if selector == #selector(URLSessionDelegate.urlSessionDidFinishEvents(forBackgroundURLSession:)) {
            return sessionDidFinishEventsForBackgroundURLSession != nil
        }
    #endif
   //省略了一些代码
}

是不是很6啊?不用我们再写代理,也不用再写代理方法的实现了,Alamofire帮我们省了这一步了。

Alamofire这些优秀的框架能帮我们省很多的代码,但我们也不能忘了原生API的基础哦

相关文章

  • Alamofire实现后台下载

    咔咔咔,敲完一个Alamofire的下载实现: 切到后台时,下载不继续执行,切回后,下载继续执行,后台下载的目的没...

  • Alamofire-后台下载

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

  • Alamofire-后台下载及SessionManger流程分析

    我们在Alamofire-URLSession中讲到过URLSession实现的后台,我们用Alamofire实现...

  • Alamofire ——后台下载

    我们先从基本的URLSession后台下载入手,对比看下Alamofire的后台下载 URLSession后台下载...

  • Alamofire(三)-- 后台下载

    这次我们来讲一讲Alamofire的后台下载,实际项目中,也有很多时候需要使用到后台下载的需求。Alamofire...

  • Alamofire - 后台下载

    上一篇有略讲URLSession处理后台下载 Alamofire(一) 这一篇来研究下Alamofire - 后台...

  • Alamofire后台下载

    最近在使用Alamofire 后台下载时遇到一个问题, 正在下载任务的程序退出到后台再回到前台UI没有刷新. 为了...

  • Alamofire(一)后台下载基本使用及原理解析

    前言 这篇文章主要是分析后台下载,通过先写URLSession的后台下载,然后使用Alamofire这两种不同的情...

  • Alamofire之后台下载

    后台下载的一般代码写法如下: 一步步分析,首先查看SessionManager.default到底做了什么: co...

  • Alamofire-后台下载

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

网友评论

      本文标题:Alamofire实现后台下载

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