Alamofire學習(一)網絡基礎swift
@TOC緩存
Alamofire中是使用URLSession進行封裝的,因此有必要去先深刻了解下URLSession. URLSession等同於NSURLSession,只是前者是Swift中的名字,後者是OC中的名字,他們之間是能夠直接相互轉換的。NSURLSession是同iOS7一同推出的,主要是對NSURLConnection進行了重構和優化,而且NSURLConnection在iOS 9的時候也已經被廢棄,因此NSURLSession是NSURLConnection的取代者。安全
Alamofire是一個爲iOS和macOS打造的並基於Swift的網絡庫.它在Apple的基礎網絡架構上提供了更加優雅的接口來簡化繁重而經常使用的網絡請求任務。 Alamofire提供了鏈式的request/response方法,JSON的傳參和響應序列化,身份認證和其餘特性。Alamofire的優雅之處在於它完徹底全是由Swift寫成的,而且沒有從它的Objective-C版本-AFNetworking那繼承任何特性。服務器
由於咱們的Alamofire
是對蘋果URLSession
的封裝的網絡框架,因此在探索Alamofire
以前,咱們除了須要掌握一些必備的網絡相關知識外,還須要熟悉IOS的系統API URLSession
。markdown
先來看一張概要圖:cookie
會話模式 | 特色 | 描述 |
---|---|---|
默認會話模式(default) | 工做模式相似於原來的NSURLConnection,使用的是基於磁盤緩存的持久化策略,使用用戶keychain中保存的證書進行認證受權。 | 默認模式,一般咱們用這種模式就足夠了。default模式下系統會建立一個持久化的緩存並在用戶的鑰匙串中存儲證書 |
瞬時會話模式(ephemeral) | 該模式不使用磁盤保存任何數據。全部和會話相關的caches,證書,cookies等都被保存在RAM中,所以當程序使會話無效,這些緩存的數據就會被自動清空。 | 系統沒有任何持久性存儲,全部內容的生命週期都與session相同,當session無效時,全部內容自動釋放。 |
後臺會話模式(background) | 該模式在後臺完成上傳和下載,在建立Configuration對象的時候須要提供一個NSString類型的ID用於標識完成工做的後臺會話。 | background建立一個能夠在後臺甚至APP已經關閉的時候仍然在傳輸數據的會話。background模式與default模式很是類似,不過background模式會用一個獨立線程來進行數據傳輸。background模式能夠在程序掛起,退出,崩潰的狀況下運行task。也能夠利用標識符來恢復進。注意,後臺Session必定要在建立的時候賦予一個惟一的identifier,這樣在APP下次運行的時候,可以根據identifier來進行相關的區分。若是用戶關閉了APP,IOS 系統會關閉全部的background Session。並且,被用戶強制關閉了之後,IOS系統不會主動喚醒APP,只有用戶下次啓動了APP,數據傳輸纔會繼續 |
URLSessionDataTask: 處理從HTTP get請求中從服務器獲取數據到內存中。網絡
Use URLSession’s dataTask(with:) and related methods to create URLSessionDataTask instances. Data tasks request a resource, returning the server’s response as one or more NSData objects in memory. They are supported in default, ephemeral, and shared sessions, but are not supported in background sessionssession
URLSessionUploadTask:上傳硬盤中的文件到服務器,通常是HTTP POST 或 PUT方式
Use URLSession’s uploadTask(with:from:) and related methods to create URLSessionUploadTask instances. Upload tasks are like data tasks, except that they make it easier to provide a request body so you can upload data before retrieving the server’s response. Additionally, upload tasks are supported in background sessions.
URLSessionDownloadTask: 從遠程服務器下載文件到臨時文件位置
Use URLSession’s downloadTask(with:) and related methods to create URLSessionDownloadTask instances. Download tasks download a resource directly to a file on disk. Download tasks are supported in any type of session.
Use URLSession’s streamTask(withHostName:port:) or streamTask(with:) to create URLSessionStreamTask instances. Stream tasks establish a TCP/IP connection from a host name and port or a net service object.
緩存策略 | 做用 | 說明 |
---|---|---|
NSURLRequestUseProtocolCachePolicy = 0 | 默認緩存策略 | 若是一個NSCachedURLResponse對於請求並不存在,數據將會從源端獲取。若是請求擁有一個緩存的響應,那麼URL加載系統會檢查這個響應來決定,若是它指定內容必須從新生效的話。假如內容必須從新生效,將創建一個連向源端的鏈接來查看內容是否發生變化。假如內容沒有變化,那麼響應就從本地緩存返回數據。若是內容變化了,那麼數據將從源端獲取 |
NSURLRequestReloadIgnoringLocalCacheData = 1 | URL應該加載源端數據,不使用本地緩存數據 | |
NSURLRequestReloadIgnoringLocalAndRemoteCacheData =4 | 本地緩存數據、代理和其餘中介都要忽視他們的緩存,直接加載源數據 | |
NSURLRequestReloadIgnoringCacheData | = NSURLRequestReloadIgnoringLocalCacheData | |
NSURLRequestReturnCacheDataElseLoad = 2 | 指定已存的緩存數據應該用來響應請求,無論它的生命時長和過時時間。若是在緩存中沒有已存數據來響應請求的話,數據從源端加載 | |
NSURLRequestReturnCacheDataDontLoad = 3 | 指定已存的緩存數據用來知足請求,無論生命時長和過時時間。若是在緩存中沒有已存數據來響應URL加載請求的話,不去嘗試從源段加載數據,此時認爲加載請求失敗。這個常量指定了一個相似於離線模式的行爲 | |
NSURLRequestReloadRevalidatingCacheData = 5 | 指定若是已存的緩存數據被提供它的源段確認爲有效則容許使用緩存數據響應請求,不然從源段加載數據。 |
屬性類別 | 屬性名稱 | 做用 |
---|---|---|
常規 | ||
常規 | identifier | 配置對象的後臺會話標識符 |
常規 | httpAdditionalHeaders | 與請求一塊兒發送的附加頭文件的字典 |
常規 | networkServiceType | 網絡服務的類型 |
常規 | allowsCellularAccess | 一個布爾值,用於肯定是否應經過蜂窩網絡進行鏈接 |
常規 | timeoutIntervalForRequest | 等待其餘數據時使用的超時間隔 |
常規 | timeoutIntervalForResource | 資源請求應該容許的最大時間量 |
常規 | sharedContainerIdentifier | 應該下載後臺URL會話中的文件的共享容器的標識符 |
常規 | waitsForConnectivity | 一個布爾值,指示會話是否應等待鏈接變爲可用或者當即失敗 |
設置Cookie政策 | ||
httpCookieAcceptPolicy | 決定什麼時候應該接受Cookie的策略常量 | |
httpShouldSetCookies | 一個布爾值,用於肯定請求是否應包含來自Cookie存儲的Cookie | |
httpCookieStorage | 管理cookie存儲的單一對象(共享實例) | |
HTTPCookie | 表示HTTP cookie的對象。它是一個不可變的對象,從包含cookie屬性的字典中初始化 | |
設置安全策略 | ||
tlsMaximumSupportedProtocol | 在此會話中進行鏈接時客戶端應請求的最大TLS協議版本 | |
tlsMinimumSupportedProtocol | 協議協商期間應該接受的最小TLS協議 | |
urlCredentialStorage | 提供身份驗證憑據的憑證存儲 | |
設置緩存策略 | ||
urlCache | 用於向會話中的請求提供緩存響應的URL緩存 | |
requestCachePolicy | 一個預約義常量,用於肯定什麼時候從緩存中返回響應 | |
支持後臺轉移 | ||
sessionSendsLaunchEvents | 一個布爾值,指示在傳輸完成時是否應該在後臺繼續或啓動應用程序 | |
isDiscretionary | 一個布爾值,用於肯定是否能夠根據系統的判斷來調度後臺任務以得到最佳性能 | |
支持自定義協議 | ||
protocolClasses | 在會話中處理請求的額外協議子類的數組 | |
URLProtocol | 一個NSURLProtocol對象處理加載協議特定的URL數據。在NSURLProtocol類自己是一個抽象類,能夠爲與特定URL方案的URL處理基礎設施。您能夠爲您的應用支持的任何自定義協議或URL方案建立子類 | |
支持多路徑TCP | ||
multipathServiceType | 指定用於經過Wi-Fi和蜂窩接口傳輸數據的多路徑TCP鏈接策略的服務類型 | |
URLSessionConfiguration.MultipathServiceType | 指定多路徑TCP使用的服務類型的常量 | |
設置HTTP策略和代理屬性 | ||
httpMaximumConnectionsPerHost | 同時鏈接到給定主機的最大數量 | |
httpShouldUsePipelining | 一個布爾值,用於肯定會話是否應使用HTTP流水線 | |
connectionProxyDictionary | 包含有關在此會話中使用的代理信息的字典 | |
支持鏈接變化 | ||
waitsForConnectivity | 一個布爾值,指示會話是否應等待鏈接變爲可用或者當即失敗 | |
屬性類別 | 屬性名稱 | 做用 |
詳情能夠參考:蘋果官方文檔:Uploading Streams of Data
func postsesssionUploadTask(){ //1.建立會話對象 let config:URLSessionConfiguration=URLSessionConfiguration.default let session:URLSession=URLSession.init(configuration: config, delegate: self, delegateQueue: OperationQueue.main) //2.根據會話對象建立task let urlstr="\(BASEURL)"+LUNBOURL let urls: NSURL = NSURL(string: urlstr)! //3.建立可變的請求對象 var request:URLRequest = URLRequest(url: urls as URL) //4.修改請求方法爲POST request.httpMethod = "POST" //5.設置請求體-----能夠不設置,有默認的 request.httpBody = "".data(using: String.Encoding.utf8) //6.根據會話對象建立一個Task(發送請求) /* 第一個參數:請求對象 第二個參數:completionHandler回調(請求完成【成功|失敗】 data:響應體信息(指望的數據) response:響應頭信息,主要是對服務器端的描述 error:錯誤信息,若是請求失敗,則error有值 upDta:要上傳的二進制數據 */ let images:UIImage=UIImage.init(named: "bannerhomeOne")! let upData:Data=UIImagePNGRepresentation(images)! //經過data數據上傳 let upTask=session.uploadTask(with: request, from: upData) { (data, res, error) in //上傳完畢後 if error != nil{ print(error) }else{ let str = String(data: data!, encoding: String.Encoding.utf8) print("上傳完畢:\(str)") } } upTask.resume() } 複製代碼
let configuration = URLSessionConfiguration.background(withIdentifier: self.createID()) let session = URLSession.init(configuration: configuration, delegate: self, delegateQueue: OperationQueue.main) session.downloadTask(with: url).resume() 複製代碼
//下載完成以後就回調URLSessionDownloadDelegate代理 func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didFinishDownloadingTo location: URL) { print("下載完成 - \(location)") } 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") } 複製代碼
後臺下載除了須要普通下載的必須步驟(1,2)外還需作以下處理
//用於保存後臺下載的completionHandler var backgroundSessionCompletionHandler: (() -> Void)? func application(_ application: UIApplication, handleEventsForBackgroundURLSession identifier: String, completionHandler: @escaping () -> Void) { self.backgroundSessionCompletionHandler = completionHandler } 複製代碼
func urlSessionDidFinishEvents(forBackgroundURLSession session: URLSession) { print("後臺任務下載回來") DispatchQueue.main.async { guard let appDelegate = UIApplication.shared.delegate as? AppDelegate, let backgroundHandle = appDelegate.backgroundSessionCompletionHandler else { return } backgroundHandle() } } 複製代碼
var downloadTask : NSURLSessionDownloadTask? var partialData : NSData? var session : NSURLSession? var request : NSMutableURLRequest? 複製代碼
//開始下載 @IBAction func onDownLoad(sender: AnyObject) { self.downloadFile() } //掛起下載 @IBAction func onSuspend(sender: AnyObject) { if(self.downloadTask != nil) { //掛起下載任務,將下載好的數據進行保存 self.downloadTask?.cancelByProducingResumeData({ (resumeData:NSData!) -> Void in self.partialData = resumeData self.downloadTask = nil }) } // downloadTask!.suspend() } //恢復下載 @IBAction func onResume(sender: AnyObject) { if(self.downloadTask == nil) { //判斷是否又已下載數據,有的話就斷點續傳,沒有就徹底從新下載 if(self.partialData != nil) { self.downloadTask = self.session?.downloadTaskWithResumeData(self.partialData!) } else{ self.downloadTask = self.session?.downloadTaskWithRequest(self.request!) } } downloadTask!.resume() } //開始下載文件 func downloadFile() { NSLog("正在下載") //建立URL var urlStr:NSString = NSString(string: "http://cdn.wall88.com/51a317b5ef36713194.jpg") urlStr = urlStr.stringByAddingPercentEscapesUsingEncoding(NSUTF8StringEncoding)! var url = NSURL(string: urlStr)! //建立請求 request = NSMutableURLRequest(URL: url) //建立默認會話 var sessionConfig : NSURLSessionConfiguration = NSURLSessionConfiguration.defaultSessionConfiguration() sessionConfig.timeoutIntervalForRequest = 20 //設置請求超時時間 sessionConfig.allowsCellularAccess = true //是否容許蜂窩網絡下載 //建立會話 session = NSURLSession(configuration: sessionConfig, delegate: self, delegateQueue: nil)//指定配置和代理 downloadTask = session!.downloadTaskWithRequest(request!) downloadTask!.resume() } 複製代碼
//設置頁面狀態 func setUIStatus(totalBytesWritten : Int64,expectedToWrite totalBytesExpectedToWrite:Int64 ) { //調用主線程刷新UI dispatch_async(dispatch_get_main_queue(), { if(Int(totalBytesExpectedToWrite) != 0 && Int(totalBytesWritten) != 0) { //更新進度條 self.ps.progress = Float(Float(totalBytesWritten) / Float(totalBytesExpectedToWrite)) if(totalBytesExpectedToWrite == totalBytesWritten) { self.lbl_hint.text! = "下載完畢" UIApplication.sharedApplication().networkActivityIndicatorVisible = false self.btn_download.enabled = true } else{ self.lbl_hint.text = "正在下載" UIApplication.sharedApplication().networkActivityIndicatorVisible = true } } } ) } 複製代碼
//任務完成,不論是否下載成功 func URLSession(session: NSURLSession, task: NSURLSessionTask, didCompleteWithError error: NSError?) { self.setUIStatus(0, expectedToWrite: 0) if(error != nil) { NSLog("error is:\(error!.localizedDescription)") } } //下載完成 func URLSession(session: NSURLSession, downloadTask: NSURLSessionDownloadTask, didFinishDownloadingToURL location: NSURL) { var error:NSError? var cachePath : NSString = NSSearchPathForDirectoriesInDomains(NSSearchPathDirectory.CachesDirectory, NSSearchPathDomainMask.UserDomainMask, true).first as NSString var savePath = cachePath.stringByAppendingPathComponent(lbl_title.text!) NSLog("\(savePath)") var saveUrl : NSURL = NSURL(fileURLWithPath: savePath)! var defalutManager = NSFileManager.defaultManager() //判斷文件是否存在,存在則刪除 if(defalutManager.fileExistsAtPath(savePath)) { defalutManager.removeItemAtPath(savePath, error: &error) } //下載成功後,文件是保存在一個臨時的目錄中的,須要本身拷置到該文件的目錄 defalutManager.copyItemAtURL(location, toURL: saveUrl, error: &error) if(error != nil) { NSLog("\(error)") } } //下載中 func URLSession(session: NSURLSession, downloadTask: NSURLSessionDownloadTask, didWriteData bytesWritten: Int64, totalBytesWritten: Int64, totalBytesExpectedToWrite: Int64) { self.setUIStatus(totalBytesWritten, expectedToWrite: totalBytesExpectedToWrite) } 複製代碼
參考大神博客:juejin.cn/post/684490…