😊😊😊Alamofire專題目錄,歡迎及時反饋交流 😊😊😊前端
Alamofire 目錄直通車 --- 和諧學習,不急不躁!swift
上一篇 Alamofire-後臺下載 其中就介紹了關於
SesssionManager
到SessionDelegate
的分層!下面我在總結一下,而後開始一個Alamofire
很是重要的模塊Request
!數組
SesssionManager
就是對外提供的管理者,這個管理者具有整個 Alamofire
的全部功能。安全
request
請求、download、upload、stream
session
直接對外提供,方便自由處理URLSessionConfiguration
的配置模式backgroundCompletionHandler
後臺下載回來監聽閉包SesssionManager
把 Session
的代理移交給了一個專門的類 : SessionDelegate
SessionDelegate
實現了 URLSessionDelegate
、 URLSessionTaskDelegate
、 URLSessionDataDelegate
、 URLSessionDownloadDelegate
、 URLSessionStreamDelegate
等代理bash
更多有意思的是:SessionDelegate
還提供了對外的閉包,意味着全部的內部實現的代理狀況,再外界均可以進行監聽。固然這個全部的對外閉包分爲兩種狀況:markdown
總結:
SesssionManager
負責建立和管理Request
對象及其底層NSURLSession
網絡
首先給你們貼出一張很是熟悉的圖,看懂了這張圖對下面理解 Request
的幫助大大的session
SesssionManager
,他給外界的用戶提供了不少的功能iOS、Android、前端、後臺、測試
實現的!iOS
模塊的任務來講,有 首頁、發現、個人、SDK、視頻....
模塊要實現,可是咱們的項目經理有可能都不知道這些究竟是什麼,怎麼實現!全部來講若是所有交給SesssionManager
來實現,顯然耦合性過強,還有任務亂七八糟,沒有體現一個牛逼項目分層架構的效果。因此在 iOS
任務細化和SesssionManager
之間就缺了一個小管理者,對下:他知道具體事務和調度。對上:他能和SesssionManager
協調配合。那就是 Request
首先說明一下 Alamofire
支持編碼格式,具體格式差別根據名字很容易理解,實在不能理解的能夠自行百度查漏補缺閉包
let encodedURLRequest = try encoding.encode(originalRequest!, with: parameters)
經過這句代碼還編碼請求架構
public func encode(_ urlRequest: URLRequestConvertible, with parameters: Parameters?) throws -> URLRequest { var urlRequest = try urlRequest.asURLRequest() guard let parameters = parameters else { return urlRequest } if let method = HTTPMethod(rawValue: urlRequest.httpMethod ?? "GET"), encodesParametersInURL(with: method) { guard let url = urlRequest.url else { throw AFError.parameterEncodingFailed(reason: .missingURL) } if var urlComponents = URLComponents(url: url, resolvingAgainstBaseURL: false), !parameters.isEmpty { let percentEncodedQuery = (urlComponents.percentEncodedQuery.map { $0 + "&" } ?? "") + query(parameters) urlComponents.percentEncodedQuery = percentEncodedQuery urlRequest.url = urlComponents.url } } else { if urlRequest.value(forHTTPHeaderField: "Content-Type") == nil { urlRequest.setValue("application/x-www-form-urlencoded; charset=utf-8", forHTTPHeaderField: "Content-Type") } urlRequest.httpBody = query(parameters).data(using: .utf8, allowLossyConversion: false) } return urlRequest } 複製代碼
代碼自行查閱,這裏總結一下
首先取出請求方法,根據不一樣的請求方法,參數編碼是不一樣的
.get, .head, .delete
這三個方法是把參數直接拼接到 URL
後面httpBody
) 的形式編碼由於咱們的請求是經過 ASCII編碼
的,因此要進行百分號編碼,第一步就是對當前請求的全部路由百分號編碼
參數便利編碼, 拼接拿出
private func query(_ parameters: [String: Any]) -> String { var components: [(String, String)] = [] for key in parameters.keys.sorted(by: <) { let value = parameters[key]! components += queryComponents(fromKey: key, value: value) } return components.map { "\($0)=\($1)" }.joined(separator: "&") } 複製代碼
ASCII
有小到大進行排序queryComponents
這個方法代碼過分省略。
key和value
取出,而後進行了百分號編碼。($0)=\($1)
&
普通方法就直接拼接到URL的後面,例如POST方法就是把這些編碼好的參數對放入請求體中。其中還要加入Content-Type
的請求頭
探索完 request
繁雜事務之一的參數編碼以後,開始分析內部:url -> request -> task
的過程。這個過程當中還創建 task以及request
之間的綁定關係
open func request(_ urlRequest: URLRequestConvertible) -> DataRequest { var originalRequest: URLRequest? do { originalRequest = try urlRequest.asURLRequest() let originalTask = DataRequest.Requestable(urlRequest: originalRequest!) let task = try originalTask.task(session: session, adapter: adapter, queue: queue) let request = DataRequest(session: session, requestTask: .data(originalTask, task)) delegate[task] = request if startRequestsImmediately { request.resume() } return request } catch { return request(originalRequest, failedWith: error) } } 複製代碼
Requestable
來幫助下層的 DataRequest
建立 Task
,也是常規說法,任務分層,架構思路更清晰task 和 request
, 方便在 SessionDelegate
下發任務,task
直接檢索,request
方便直接獲取request.resume()
啓動Request
初始化的時候利用了枚舉的便利性,構造建立,相關信息保存可能不少小夥伴這個時候就會有疑慮,你不就是經過SessionDelegate
實現代理, 爲何這裏還要有一個 DataTaskDelegate
首先必定要明白 SessionDelegate
是全部 Session
的代理遵循者,任何的代理都會來到這裏響應。
DataTaskDelegate
是咱們具體繁瑣任務實現者,這裏面全部方法都是由 SessionDelegate
下發響應的。
說白了就是總體與局部的關係
SessionDelegate
是事件總響應者,可是具體的事務應該交給具體的人去執行,不能由於在 SessionDelegate
可以拿到全部的響應,那麼全部的代碼都羅列在這裏,很顯然若是那樣作必然會致使混亂,咱們根據不一樣的需求,響應總代理而後根據需求的不一樣交給專業的人去作專業的事。耦合性大大下降,架構的分層更加明顯。
其中還有異步很是重要的點:delegate[task] = request
給咱們的SessionDelegate
提供一個方便及時得到能力
open func urlSession( _ session: URLSession, downloadTask: URLSessionDownloadTask, didFinishDownloadingTo location: URL) { // 省略屬性閉包回調的狀況 if let delegate = self[downloadTask]?.delegate as? DownloadTaskDelegate { delegate.urlSession(session, downloadTask: downloadTask, didFinishDownloadingTo: location) } } 複製代碼
task
找到相應的 Request
而後由於屬性關係,直接拿出 Request
的屬性delegate 來處理相關事務func urlSession( _ session: URLSession, downloadTask: URLSessionDownloadTask, didFinishDownloadingTo location: URL) { temporaryURL = location guard let destination = destination, let response = downloadTask.response as? HTTPURLResponse else { return } let result = destination(location, response) let destinationURL = result.destinationURL let options = result.options self.destinationURL = destinationURL do { if options.contains(.removePreviousFile), FileManager.default.fileExists(atPath: destinationURL.path) { try FileManager.default.removeItem(at: destinationURL) } if options.contains(.createIntermediateDirectories) { let directory = destinationURL.deletingLastPathComponent() try FileManager.default.createDirectory(at: directory, withIntermediateDirectories: true) } try FileManager.default.moveItem(at: location, to: destinationURL) } catch { self.error = error } } 複製代碼
SessionDelegate
所須要知道的!咱們從
SessionManager
->Request
這一過程明面上就是直接交付,可是背地都是經過代理響應聯通的:SessionDelegate
->具體的Request的delegate
。看到這裏,是否是感受很是的爽!優秀的框架老是可以給你在思想方面帶來很大的提高,咱們平時開發的時候也會有很噁心的耦合度,通信問題。那麼想必Alamofire
的設計思路確定可以給你帶來必定的啓示!就問此時此刻還有誰?45度仰望天空,該死!我這無處安放的魅力!