😊😊😊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度仰望天空,该死!我这无处安放的魅力!