😊😊😊Alamofire专题目录,欢迎及时反馈交流 😊😊😊swift
Alamofire 目录直通车 --- 和谐学习,不急不躁!api
这一篇主要讲解后台下载,后台下载对于应用程序来讲,是一个很是重要也比较好用的功能。虽然用好后台下载的确可以大大提高用户体验,可是又不少时候咱们也会遇到不少坑点以及疑惑点。其中会经过
URLSession
和Alamofire
两种形式分别展开讨论,对比学习才能更能体会Alamofire
的设计思惟。Alamofire
持续更新中,但愿你们但愿!安全
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
的模式的 configuration
。configuration
有 三种模式 ,只有background
的模式才能进行后台下载。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")
}
}
复制代码
URLSessionDownloadDelegate
的 didFinishDownloadingTo
代理,实现下载完成转移临时文件里的数据到相应沙盒保存urlSession(_ session: downloadTask:didWriteData bytesWritten: totalBytesWritten: totalBytesExpectedToWrite: )
的代理监听下载进度http的分片传输
才致使的进度有段的感受,其实证实内部也是对这个代理方法不断调用,才能进度回调!这里实现了下载功能,可是对于咱们须要的后台下载还差一段session
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.闭包
苹果爸爸老是能在合适时间给你优秀的建议,阅读文档的能力决定你是否可以在这个时代站稳本身的脚尖app
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
的回调函数执行那么若是不实现这个代理里面的回调函数的执行,那么会发生什么呢async
Warning: Application delegate received call to -
application:handleEventsForBackgroundURLSession:completionHandler:
but the completion handler was never called.
复制代码
Alamofire
框架仍是比较有感受的,这个节奏也是函数式回调,还支持链式请求和响应!事务逻辑很是清晰,还有代码可读性也是很是简洁ide
LGBackgroundManger.shared.manager
.download(self.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!,[.removePreviousFile,.createIntermediateDirectories])
}
.response { (downloadResponse) in
print("下载回调信息: \(downloadResponse)")
}
.downloadProgress { (progress) in
print("下载进度 : \(progress)")
}
复制代码
LGBackgroundManger
的后台下载管理类,调用manger
的手法也是很是直接。struct LGBackgroundManger {
static let shared = LGBackgroundManger()
let manager: SessionManager = {
let configuration = URLSessionConfiguration.background(withIdentifier: "com.lgcooci.AlamofireTest.demo")
configuration.httpAdditionalHeaders = SessionManager.defaultHTTPHeaders
configuration.timeoutIntervalForRequest = 10
configuration.timeoutIntervalForResource = 10
configuration.sharedContainerIdentifier = "group.com.lgcooci.AlamofireTest"
return SessionManager(configuration: configuration)
}()
}
复制代码
可能不少同窗都在质疑为何要作成单利,URLSession的时候不是挺好的?
SessionManager.defalut
显然是不能够的!毕竟要求后台下载,那么咱们的会话 session
的配置 URLSessionConfiguration
是要求 background
模式的Error Domain=NSURLErrorDomain Code=-999 "cancelled"
AppDelegate
的回调方便直接接收func application(_ application: UIApplication, handleEventsForBackgroundURLSession identifier: String, completionHandler: @escaping () -> Void) {
LGBackgroundManger.shared.manager.backgroundCompletionHandler = completionHandler
}
复制代码
一篇优秀的博客,毕竟还要跟你们交代这样清晰的代码的背后流程
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)
}
复制代码
session
,其中configuration
是 default
的模式,设置了一些基本的 SessionManager.defaultHTTPHeaders
请求头信息SessionDelegate
这个专门处理代理的类来实现 URLSession
的代理SessionDelegate 是一个很是重要的类,集合全部的代理
这里咱们根据需求来到 urlSessionDidFinishEvents
的代理
open func urlSessionDidFinishEvents(forBackgroundURLSession session: URLSession) {
sessionDidFinishEventsForBackgroundURLSession?(session)
}
复制代码
sessionDidFinishEventsForBackgroundURLSession
闭包的执行,那么这个闭包在何时申明的呢?SessionDelegate
只是处理代理的专门类,但不是逻辑数据的处理类,按照封装设计的常规思路必将交给管理者类来下发在咱们的 SessionManger
里面的初始化的时候,有一个方法commonInit
delegate.sessionDidFinishEventsForBackgroundURLSession = { [weak self] session in
guard let strongSelf = self else { return }
DispatchQueue.main.async { strongSelf.backgroundCompletionHandler?() }
}
复制代码
delegate.sessionDidFinishEventsForBackgroundURLSession
闭包的声明backgroundCompletionHandler
, 这也是 SessionManger
对外提供的功能!聪明的你应该知道知道了我在application
的操做的本质了!handleEventsForBackgroundURLSession
方法里,把回调闭包传给了 SessionManager 的 backgroundCompletionHandler
urlSessionDidFinishEvents
代理的调用 -> sessionDidFinishEventsForBackgroundURLSession
调用sessionDidFinishEventsForBackgroundURLSession
执行 -> SessionManager 的 backgroundCompletionHandler
的执行completionHandler
的调用不管你是使用
URLSession
的方式,仍是Alamofire
进行后台下载,可是原理仍是同样的,只是Alamofire
使用更加达到依赖下沉,网络层下沉,使用更简洁,这也是不少时候咱们须要第三方框架的缘由。这一篇你估计已经感觉到了Alamofire
的舒服,那么若是你喜欢的话,麻烦点心,关注一下。我会持续更新一个Alamofire
的系列专题,谢谢!就问此时此刻还有谁?45度仰望天空,该死!我这无处安放的魅力!