Alamofire的Request解析

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进行处理并保存在自己的属性里
分步骤详细解析 我们还是从最基础的DataRequest的一个方法来逐行进行分析
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的方法,所以我们知道,你可以传任意类型哪怕是一个PigClass类,只要实现这个协议方法能够返回URLRequest即可,从这里我们可以看到但凡是后缀是Convertible的协议都是类似于这样的便利方法,就像我们前面分析过的URLConvertible一样
  • 通过TaskConvertible获取到URLSessionTask且对urlRequest进行自定义加工
    1. 通过TaskConvertible获取到URLSessionTask
      let originalTask = DataRequest.Requestable(urlRequest: originalRequest!)

      这里的originalTask类型其实是DataRequest的结构体Requestable的一个实例初始化需要传入urlRequest,而这个结构体遵守了协议TaskConvertible,所以我们知道这里可以获取到URLSessionTask
    2. urlRequest进行自定义加工
      在协议TaskConvertible的方法声明我们看到传递了一个 RequestAdapter 的参数,且在结构体Requestable的协议实现内我们可以看到这行
      let urlRequest = try self.urlRequest.adapt(using: adapter)

      点击这里self.urlRequestadapt方法
      func adapt(using adapter: RequestAdapter?) throws -> URLRequest{ guard let adapter = adapter else { return self } return try adapter.adapt(self) }

      是不是绕晕了???哈哈,只能说作者封装的太仔细了
      其实这里的RequestAdapter协议就是专门对URLRequest加工的一个协议,从它的协议声明方法可以看出。
    3. 返回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父类Requestinit方法,其第三个参数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()方法本质上都是控制taskDelegatetask对象。
  • TaskDelegatequeue
    前面我们可以看到通过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

    推荐阅读