😊😊😊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度仰望天空,該死!我這無處安放的魅力!