Alamofire的Request解析
文章图片
女神镇楼
上一篇我们主要说了一下首先我们看下一个普通的请求的流程经过了哪些步骤 之前分析过Alamofire
中对一个普通的DataRequest
的响应序列化的步骤。这次我们针对Requset
的一个过程简要分析下
Alamofire
中的静态方法都是调用SessionManager
里面的方法,SessionManager
里的default
存放着默认的session
,而SessionDelegate
则实现了session
的代理。private func commonInit(serverTrustPolicyManager: ServerTrustPolicyManager?) {
session.serverTrustPolicyManager = serverTrustPolicyManager
///这里设置了代理
delegate.sessionManager = selfdelegate.sessionDidFinishEventsForBackgroundURLSession = { [weak self] session in
guard let strongSelf = self else { return }
DispatchQueue.main.async { strongSelf.backgroundCompletionHandler?() }
}
}
再来看看
SessionManager
里面首先声明了许多闭包,如果你想自己定义你的接收响应的逻辑你可以实现这些闭包
// MARK: URLSessionDelegate Overrides/// Overrides default behavior for URLSessionDelegate method `urlSession(_:didBecomeInvalidWithError:)`.
open var sessionDidBecomeInvalidWithError: ((URLSession, Error?) -> Void)?/// Overrides default behavior for URLSessionDelegate method `urlSession(_:didReceive:completionHandler:)`.
open var sessionDidReceiveChallenge: ((URLSession, URLAuthenticationChallenge) -> (URLSession.AuthChallengeDisposition, URLCredential?))?
再来看看里面代理方法的实现
/// Tells the delegate that the data task has received some of the expected data.
///
/// - parameter session:The session containing the data task that provided data.
/// - parameter dataTask: The data task that provided data.
/// - parameter data:A data object containing the transferred data.
open func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive data: Data) {///如果实现了闭包,则通过闭包传递数据
if let dataTaskDidReceiveData = https://www.it610.com/article/dataTaskDidReceiveData {
dataTaskDidReceiveData(session, dataTask, data)
} else if let delegate = self[dataTask]?.delegate as? DataTaskDelegate {///否则通过保存的[task:request]来获取到request,调用其taskDelegate实例对象的方法,将数据传递给了TaskDelegate
delegate.urlSession(session, dataTask: dataTask, didReceive: data)
}
}
可以看到将数据传递到了
TaskDelegate
里,再来看下TaskDelegate
是怎么处理的func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive data: Data) {
///获取响应时间
if initialResponseTime == nil { initialResponseTime = CFAbsoluteTimeGetCurrent() }
///如果实现了闭包则通过闭包传递出去
if let dataTaskDidReceiveData = https://www.it610.com/article/dataTaskDidReceiveData {
dataTaskDidReceiveData(session, dataTask, data)
} else {if let dataStream = dataStream {
///如果实现了request的stream方法,则这里将数据通过闭包传递
dataStream(data)
} else {
///否则存储数据
mutableData.append(data)
}///计算此处请求返回数据的一个进度
let bytesReceived = Int64(data.count)
totalBytesReceived += bytesReceived
let totalBytesExpected = dataTask.response?.expectedContentLength ?? NSURLSessionTransferSizeUnknownprogress.totalUnitCount = totalBytesExpected
progress.completedUnitCount = totalBytesReceivedif let progressHandler = progressHandler {
progressHandler.queue.async { progressHandler.closure(self.progress) }
}
}
}
我们可以看到,针对一个普通的
Data
请求的话,这里的data
就保存了返回的响应数据。override var data: Data? {
if dataStream != nil {
return nil
} else {
return mutableData
}
}
所以后面在序列化返回数据的时候我们可以看到
这里的data就是获取的request.delegate.data
var dataResponse = DataResponse(
request: self.request,
response: self.response,
data: self.delegate.data,
result: result,
timeline: self.timeline
)
总的来说,一次普通的请求流程是
- 获取
URLRequest
- 获取
URLSessionTask
-
SessionDelegate
接受到代理回调传递给TaskDelegate,TaskDelegate
进行处理并保存在自己的属性里
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] = requestif startRequestsImmediately { request.resume() }return request
} catch {
return request(originalRequest, failedWith: error)
}
}
这里通过传递一个
URLRequestConvertible
类型的参数来开始一个请求- 通过
URLRequestConvertible
获取URLRequest
URLRequestConvertible
是一个协议,只有一个asURLRequest
的方法,所以我们知道,你可以传任意类型哪怕是一个Pig
的Class
类,只要实现这个协议方法能够返回URLRequest
即可,从这里我们可以看到但凡是后缀是Convertible
的协议都是类似于这样的便利方法,就像我们前面分析过的URLConvertible
一样- 通过
TaskConvertible
获取到URLSessionTask
且对urlRequest
进行自定义加工- 通过
TaskConvertible
获取到URLSessionTask
let originalTask = DataRequest.Requestable(urlRequest: originalRequest!)
这里的originalTask
类型其实是DataRequest
的结构体Requestable
的一个实例初始化需要传入urlRequest
,而这个结构体遵守了协议TaskConvertible
,所以我们知道这里可以获取到URLSessionTask
- 对
urlRequest
进行自定义加工
在协议TaskConvertible
的方法声明我们看到传递了一个RequestAdapter
的参数,且在结构体Requestable
的协议实现内我们可以看到这行
let urlRequest = try self.urlRequest.adapt(using: adapter)
点击这里self.urlRequest
的adapt
方法
func adapt(using adapter: RequestAdapter?) throws -> URLRequest{ guard let adapter = adapter else { return self } return try adapter.adapt(self) }
是不是绕晕了???哈哈,只能说作者封装的太仔细了
其实这里的RequestAdapter
协议就是专门对URLRequest
加工的一个协议,从它的协议声明方法可以看出。
- 返回
URLSessionTask
许多人可能对最后的返回觉得很奇怪
return queue.sync { session.dataTask(with: urlRequest) }
这里返回的是URLSessionTask
么??点击这个sync方法你就可以看到了
public func sync
(execute work: () throws -> T) rethrows -> T
最后返回的是一个泛型函数,而这个泛型函数返回的结果就是函数参数() throws -> T
返回的值,而session.dataTask(with: urlRequest)
返回的是URLSessionTask
- 通过
- 对
request
进行包装
let request = DataRequest(session: session, requestTask: .data(originalTask, task))
这里调用的是DataRequest
父类Request
的init
方法,其第三个参数requestTask
是一个枚举类型,用来对request
进行分类并关联值的,在这个init
方法里面我们可以看到
case .data(let originalTask, let task): taskDelegate = DataTaskDelegate(task: task) self.originalTask = originalTask
这里用我们之前获取到的sessionTask
来初始化DataTaskDelegate
,而之前我们说了TaskDelegate
以及其子类是我们最终接收Session
响应的地方。
- 一个
request
请求的开始、暂停、结束
通过上面我们能看到初始化了一个DataTaskDelegate
对象,我们看初始化方法
init(task: URLSessionTask?) { _task = taskself.queue = { let operationQueue = OperationQueue()operationQueue.maxConcurrentOperationCount = 1 operationQueue.isSuspended = true operationQueue.qualityOfService = .utilityreturn operationQueue }() }
一个request
对应着一个TaskDelegate
对象,我们再来看Request
中的resume()
、suspend()
、cancel()
方法本质上都是控制taskDelegate
的task
对象。
-
TaskDelegate
的queue
前面我们可以看到通过Request
获得URLSessionTask
,然后执行任务。而这些任务是在SessionManager
的一个queue
这个队列里同步进行的。这个queue
是初始化SessionManager
时候用uuid
生成的一个不会重复的队列
let queue = DispatchQueue(label: "org.alamofire.session-manager." + UUID().uuidString)
所以所有的网络请求,如果我们用的是同一个session
的话,那么这些请求虽然是在后台执行的,但是是同步的。所以有时同时处理多个请求时,我们可以采用多个session
。
而TaskDelegate
里也有一个queue
,
/// The serial operation queue used to execute all operations after the task completes. open let queue: OperationQueue
这是OperationQueue类型(不熟悉的可以先了解下),从注释来看这是当任务执行完成后才会开始执行任务的一条队列。
在此文件的didCompleteWithError
方法里我们可以看到queue.isSuspended = false
,所以这是当URLSessionTask
完成之后,此queue
才开始执行,且此队列添加的第一个任务就是在Request的初始化方法里的
delegate.queue.addOperation { self.endTime = CFAbsoluteTimeGetCurrent() }
结合之前在didCompleteWithError
启动队列,所以第一个任务就是获取该请求的结束时间,后面的响应处理在前面的一篇文章中可以看到。
这次简单通过一个最终DataRequest
来分析了下请求的一个过程,后面还会写一篇文章来分析下别的类型的Request
的设计思路和我对于Alamofire
的一篇最终总结吧。希望能学习到作者的代码设计风格。
【Alamofire的Request解析】太轻易得到的往往都不会去珍惜,真正失去了却又后悔莫及。
联系方式
- GitHub: 大猫传说中的gitHud地址
- 邮箱: 1030472953@qq.com
推荐阅读
- 热闹中的孤独
- JAVA(抽象类与接口的区别&重载与重写&内存泄漏)
- 放屁有这三个特征的,请注意啦!这说明你的身体毒素太多
- 一个人的旅行,三亚
- 布丽吉特,人生绝对的赢家
- 慢慢的美丽
- 尽力
- 一个小故事,我的思考。
- 家乡的那条小河
- 《真与假的困惑》???|《真与假的困惑》??? ——致良知是一种伟大的力量