Alamofire源码学习(二): Session

往期导航:

Alamofire源码学习目录合集ios

先简单介绍基础文件Alamofire.swift:

/// Reference to `Session.default` for quick bootstrapping and examples.
public let AF = Session.default

/// Current Alamofire version. Necessary since SPM doesn't use dynamic libraries. Plus this will be more accurate.
let version = "5.4.0"
复制代码

就这两个常量, 一个是Session类的一个单例, 一个标记了当前版本号.bootstrap

Session类是ALamofire的核心类, 封装了URLSession类, 管理全部的请求调度.

1、相关属性注解:

/// 一个默认的单例
    public static let `default` = Session()

    /// 持有一个URLSession, 用来建立请求Task, 注意不能跟本对象持有的URLSessionTask产生交互, 不然会影响Alamofire内部逻辑
    public let session: URLSession
    
    /// 处理URLSession代理, URLSessionTaskDelegate, 以及请求拦截等逻辑
    public let delegate: SessionDelegate
    
    /// 内部回调执行以及状态更新的队列,必须是串行队列
    public let rootQueue: DispatchQueue
    
    /// 是否在Request建立的时候就马上发送, 该属性用来统一管理Request建立时的startImmediately参数, 默认true
    public let startRequestsImmediately: Bool
    
    /// 异步建立Request的队列,默认是rootQueue
    public let requestQueue: DispatchQueue
    
    /// 解析response的队列, 默认是rootQueue
    public let serializationQueue: DispatchQueue
    
    /// 请求拦截器接口,是RequestAdapter跟RequestRetrier的结合, 默认nil
    public let interceptor: RequestInterceptor?
    
    /// 证书信任器接口, 默认nil
    public let serverTrustManager: ServerTrustManager?
    
    /// 重定向处理器接口, 默认nil
    public let redirectHandler: RedirectHandler?
    
    /// 缓存管理接口, 默认nil
    public let cachedResponseHandler: CachedResponseHandler?
    
    /// 事件监测管理器类,处理请求生命周期各阶段的事件, 默认用下面的defaultEventMonitors以及传入的事件检测器初始化
    public let eventMonitor: CompositeEventMonitor
    
    /// 默认的事件监测器接口列表,只有一个通知事件监测器
    public let defaultEventMonitors: [EventMonitor] = [AlamofireNotifications()]

    /// 结构体, 用来保存Request跟URLSessiontask映射关系, 提供了各类方法来存取task跟request以及数量判断, 为空判断
    var requestTaskMap = RequestTaskMap()
    
    /// 当前正在请求的Request集合
    var activeRequests: Set<Request> = []
    
    /// 等待成功的回调
    var waitingCompletions: [URLSessionTask: () -> Void] = [:]
复制代码

2、初始化

Session有两个初始化方法, 一个必要初始化方法, 一个便捷初始化方法.swift

public init(session: URLSession, delegate: SessionDelegate, rootQueue: DispatchQueue, startRequestsImmediately: Bool = true, requestQueue: DispatchQueue? = nil, serializationQueue: DispatchQueue? = nil, interceptor: RequestInterceptor? = nil, serverTrustManager: ServerTrustManager? = nil, redirectHandler: RedirectHandler? = nil, cachedResponseHandler: CachedResponseHandler? = nil, eventMonitors: [EventMonitor] = []) {
        // Alamofire不支持后台下载(为啥嘞?看后面是支持的)
        precondition(session.configuration.identifier == nil,
                     "Alamofire does not support background URLSessionConfigurations.")
        // URLSession的Queue跟rootQueue必须同样
        precondition(session.delegateQueue.underlyingQueue === rootQueue,
                     "Session(session:) initializer must be passed the DispatchQueue used as the delegateQueue's underlyingQueue as rootQueue.")

        self.session = session
        self.delegate = delegate
        self.rootQueue = rootQueue
        self.startRequestsImmediately = startRequestsImmediately
        // 默认用rootQueue作target建立请求响应解析队列
        self.requestQueue = requestQueue ?? DispatchQueue(label: "\(rootQueue.label).requestQueue", target: rootQueue)
        self.serializationQueue = serializationQueue ?? DispatchQueue(label: "\(rootQueue.label).serializationQueue", target: rootQueue)
        // 四个默认nil的属性
        self.interceptor = interceptor
        self.serverTrustManager = serverTrustManager
        self.redirectHandler = redirectHandler
        self.cachedResponseHandler = cachedResponseHandler
        // 根据传入的事件监听器以及默认的监听器初始化CompositeEventMonitor对象
        eventMonitor = CompositeEventMonitor(monitors: defaultEventMonitors + eventMonitors)
        // 把组合监听器对象丢给SessionDelegate对象用来管理task
        delegate.eventMonitor = eventMonitor
        // 请求时Session变化的处理
        delegate.stateProvider = self
    }
复制代码

便捷初始化方法使用了默认的URLSessionConfiguration以及请求队列来初始化URLSession, SessionDelegate, rootQueueapi

3、deinit处理:

deinit {
        finishRequestsForDeinit()
        session.invalidateAndCancel()
    }
    func finishRequestsForDeinit() {
        //挨个通知还没完成的Request 返回sessionDeinitialized错误
        requestTaskMap.requests.forEach { request in
            rootQueue.async {
                request.finish(error: AFError.sessionDeinitialized)
            }
        }
    }
复制代码

4、所有请求处理:

//对全部正在执行的请求执行一个闭包
    public func withAllRequests(perform action: @escaping (Set<Request>) -> Void) {
        rootQueue.async {
            action(self.activeRequests)
        }
    }
    //取消所有请求
    public func cancelAllRequests(completingOnQueue queue: DispatchQueue = .main, completion: (() -> Void)? = nil) {
        withAllRequests { requests in
            requests.forEach { $0.cancel() }
            queue.async {
                completion?()
            }
        }
    }
复制代码

5、请求初始化:

先定义了RequestConvertibleRequestEncodableConvertible结构体实现URLRequestConvertible协议, 用来使用不一样参数建立URLRequestConvertible对象缓存

// 用来变换URLRequest对象的闭包
    public typealias RequestModifier = (inout URLRequest) throws -> Void
    //普通的request转换器, 使用ParameterEncoding协议对象来编码参数
    struct RequestConvertible: URLRequestConvertible {
        let url: URLConvertible//url
        let method: HTTPMethod//方法
        let parameters: Parameters?//参数
        let encoding: ParameterEncoding//参数编码对象, 默认URL编码
        let headers: HTTPHeaders?//请求头
        let requestModifier: RequestModifier?
    }
    //参数符合Encodable协议的转换器, 使用ParameterEncoder协议对象编码参数
    struct RequestEncodableConvertible<Parameters: Encodable>: URLRequestConvertible {
        let url: URLConvertible
        let method: HTTPMethod
        let parameters: Parameters?
        let encoder: ParameterEncoder
        let headers: HTTPHeaders?
        let requestModifier: RequestModifier?
    }
复制代码

对于普通request, streamRequest, downloadRequest, 都有三个建立请求的方法:sass

  1. 先使用参数建立RequestConvertible对象, 而后转换为URLRequestConvertible后使用3来建立对应的Request对象
  2. 使用RequestConvertible建立, 逻辑同1
  3. 使用URLRequestConvertible对象+rootQueue+serializationQueue+eventMonitor建立Request对象, 并指定RequestDelegate为self用来处理URLSessionConfiguration, 清理工做以及重试逻辑
  • downloadRequest有一个额外的断点续传的方法, 使用已下载的Data来初始化DownloadRequest对象

对于UploadRequest, 又定义了ParameterlessRequestConvertible结构体实现URLRequestConvertible协议, 特色是没有参数.
接着定义Upload结构体实现UploadConvertible用来封装request与uploadable
对于UploadRequest的建立使用的都是ParameterlessRequestConvertible对象, 有共计X个建立UploadRequest的方法:安全

  1. 使用data + 请求基础参数, 先生成ParameterlessRequestConvertible对象,转2
  2. 使用data, URLRequestConvertible对象, 生成Uploadable.data对象, 转11
  3. 使用fileURL + 请求基础参数, 先生成ParameterlessRequestConvertible对象, 转4
  4. 使用fileURL, ParameterlessRequestConvertible对象, 生成Uploadable.file对象, 转11
  5. 使用InputStream + 基础参数 转6
  6. 使用InputStream, ParameterlessRequestConvertible, 生成Uploadable.stream对象,转11
  7. 使用多表单闭包+请求基础参数, 执行闭包生成MultipartFormData, ParameterlessRequestConvertible, 转换为URLRequestConvertible, 转10
  8. 使用多表单闭包+URLRequestConvertible, 执行闭包, 转10
  9. 使用MultipartFormData对象+基础请求参数, 生成ParameterlessRequestConvertible, MultipartUpload, 转12
  10. 使用MultipartFormData对象+URLRequestConvertible生成MultipartUpload, 转12
  • 如下为intenal api, 外部没法访问
  1. 使用Uploadable + URLRequestConvertible, 生成Upload, 转12 (在Session中未用到)
  2. 使用UploadConvertible协议对象生成UploadRequest并发送

注意:
  1. upload方法共有12个, 本质上upload方法分为3种: data(内存), fileURL(磁盘), InputStream(磁盘), 7-10均为处理多表单数据, 参数中带有一个encodingMemoryThreshold参数, 用来决定编码内存限制, 当表单数据大小大于该限制时, 编码将把表单数据存到磁盘, 使用iostream来处理, 避免内存太高. 生成的Uploadable的类型根据表单编码类型来肯定.
  2. 全部的upload的url都没有query参数, 因此用的是ParameterlessRequestConvertible结构体来转换URLRequestConvertible协议对象.
  3. upload的12个方法 都是互相调用, 最终的数据编码, 都在对应的Request模块

6、准备发送请求

主入口为:markdown

// MARK: Perform

    /// Starts performing the provided `Request`.
    ///
    /// - Parameter request: The `Request` to perform.
    func perform(_ request: Request) {
        rootQueue.async {
            //先在rootQueue中判断是否请求被取消
            guard !request.isCancelled else { return }
            //塞入到正在请求的Request集合中
            self.activeRequests.insert(request)
            //在requestQueue队列发送请求
            self.requestQueue.async {
                // 子类必须先case不然就会被识别为父类了
                switch request {
                case let r as UploadRequest: 
                     // UploadRequest是DataRequest的子类
                    self.performUploadRequest(r)
                    //先建立Uploadable
                    //而后在rootQueue告知事件监听器didCreateUploadable, 而后调用performSetupOperations方法
                    //建立失败的话先在rootQueue告知监视器didFailToCreateUploadable, 错误消息为createUploadableFailed
                    //而后在request中决定是否重试
                case let r as DataRequest: 
                    self.performDataRequest(r)
                    //直接调performSetupOperations方法
                case let r as DownloadRequest: 
                    self.performDownloadRequest(r)
                    //对request的downloadable进行断定
                    //若是是新建下载, 直接调用performSetupOperations方法
                    //若是是断点续传, 在rootQueue调用didReceiveResumeData方法, 详见下方断点续传部分
                case let r as DataStreamRequest: 
                    self.performDataStreamRequest(r)
                    //直接调performSetupOperations方法
                default: 
                    fatalError("Attempted to perform unsupported Request subclass: \(type(of: request))")
                }
            }
        }
    }
复制代码

方法performSetupOperations接受两个参数: Request对象以及URLRequestConvertible协议对象, 后者来自于request.convertible属性. 处理成功后, 会调用didCreateURLRequest方法来更新状态session

func performSetupOperations(for request: Request, convertible: URLRequestConvertible) {
        //当前在requestQueue
        dispatchPrecondition(condition: .onQueue(requestQueue))
        //URLRequestConvertible生成的URLRequest
        let initialRequest: URLRequest

        do {
            initialRequest = try convertible.asURLRequest()
            //检测请求是否有效(get请求不能带body参数)
            try initialRequest.validate()
        } catch {
            //出错的话就在rootQueue队列上报错误
            rootQueue.async { request.didFailToCreateURLRequest(with: error.asAFError(or: .createURLRequestFailed(error: error))) }
            return
        }
        //在rootQueue通知request,初始化URLRequest成功(使用MutableState记录状态, 告知事件监听器didCreateInitialURLRequest)
        rootQueue.async { request.didCreateInitialURLRequest(initialRequest) }
        
        guard !request.isCancelled else { return }
        //检查是否有请求适配器, 内部逻辑:
        //1. 判断request的拦截器跟Session的拦截器都不为空的话, 就返回生成组合拦截器
        //2. 返回request拦截器或者Session拦截器
        guard let adapter = adapter(for: request) else {
            //没有拦截器的话直接通知
            rootQueue.async { self.didCreateURLRequest(initialRequest, for: request) }
            return
        }
        //使用拦截器中的适配器来预处理请求
        adapter.adapt(initialRequest, for: self) { result in
            do {
                let adaptedRequest = try result.get()
                try adaptedRequest.validate()
                //通知处理完成
                self.rootQueue.async {
                    request.didAdaptInitialRequest(initialRequest, to: adaptedRequest)
                    self.didCreateURLRequest(adaptedRequest, for: request)
                }
            } catch {
                //任何错误都抛出requestAdaptationFailed错误
                self.rootQueue.async { request.didFailToAdaptURLRequest(initialRequest, withError: .requestAdaptationFailed(error: error)) }
            }
        }
    }
复制代码

7、建立URLSessionTask, 发送请求

当建立请求完成, 拦截适配器处理完成以后, 就会来到这里的逻辑, 除了断点续传的请求会执行didReceiveResumeData方法, 其余的几个请求都会执行didCreateURLRequest方法, 而后最终都会调用updateStatesForTask方法来更新闭包

func didCreateURLRequest(_ urlRequest: URLRequest, for request: Request) {
        dispatchPrecondition(condition: .onQueue(rootQueue))
        //通知建立request成功
        request.didCreateURLRequest(urlRequest)

        guard !request.isCancelled else { return }
        //建立URLSessionTask, 基类Request为实现该方法, 几个子类各自实现
        let task = request.task(for: urlRequest, using: session)
        //写入Session的Request-Task数据对里保存
        requestTaskMap[request] = task
        //建立URLSessionTask成功后, request作的相关处理, 线程安全地保存task, 并通知事件监听器建立task成功
        request.didCreateTask(task)

        updateStatesForTask(task, request: request)
    }
    //基本逻辑跟上面类似, 区别就是建立task的方法不一样, 使用已下载Data建立URLSessionDownloadTask
    func didReceiveResumeData(_ data: Data, for request: DownloadRequest) {
        dispatchPrecondition(condition: .onQueue(rootQueue))

        guard !request.isCancelled else { return }

        let task = request.task(forResumeData: data, using: session)
        requestTaskMap[request] = task
        request.didCreateTask(task)

        updateStatesForTask(task, request: request)
    }
    //上面两个方法完成后会调用该方法, 开始开始发送请求
    func updateStatesForTask(_ task: URLSessionTask, request: Request) {
        //确认是在rootQueue队列更新URLSessionTask的状态
        dispatchPrecondition(condition: .onQueue(rootQueue))
        //根据request的状态来更新对应task的状态
        request.withState { state in
            switch state {
            case .initialized, .finished:
                // 初始化或者请求完成, 啥也不干
                break
            case .resumed:
                //发送请求
                task.resume()
                //告知request task开始请求
                rootQueue.async { request.didResumeTask(task) }
            case .suspended:
                //请求挂起
                task.suspend()
                rootQueue.async { request.didSuspendTask(task) }
            case .cancelled:
                //先恢复task 再取消, 保证task被取消
                task.resume()
                task.cancel()
                rootQueue.async { request.didCancelTask(task) }
            }
        }
    }
复制代码

而后等待request各自的RequestDelegate去处理请求落地的逻辑便可

8、请求适配器以及重试器:

//这两个逻辑都同样, 使用 Interceptor 类来组合Session默认的以及每一个请求单独的 适配器/重试器
    func adapter(for request: Request) -> RequestAdapter? {
        if let requestInterceptor = request.interceptor, let sessionInterceptor = interceptor {
            return Interceptor(adapters: [requestInterceptor, sessionInterceptor])
        } else {
            return request.interceptor ?? interceptor
        }
    }

    func retrier(for request: Request) -> RequestRetrier? {
        if let requestInterceptor = request.interceptor, let sessionInterceptor = interceptor {
            return Interceptor(retriers: [requestInterceptor, sessionInterceptor])
        } else {
            return request.interceptor ?? interceptor
        }
    }
复制代码

9、RequestDelegate

每个Request对象都持有一个RequestDelegate代理对象用来获取建立Request时的URLSessionConfiguration以及全局startImmediately, 而且处理错误重试与延迟重试逻辑, 指向建立Request的Session, 所以在Session中实现了RequestDelegate协议

10、SessionStateProvider

Session持有SessionDelegate用来处理Task的代理, SessionDelegate又持有一个RequestTaskMap代理指向Session, 来处理当Task状态变动时的状态处理(由于Session持有一个RequestTaskMap对象来储存Request跟NSURLSessionTask的映射关系), 所以当SessionDelegate响应URLSessionDelegate以及各个NSURLSessionTask的代理回调时, 会回调到Session中的SessionStateProvider相关协议方法中,来根据Task取得对应的Request, 并判断是否请求完成断开映射关系。

//全部操做都在rootQueue进行
extension Session: SessionStateProvider {
    func request(for task: URLSessionTask) -> Request? {
        dispatchPrecondition(condition: .onQueue(rootQueue))
        //根据task获取Request
        return requestTaskMap[task]
    }

    func didGatherMetricsForTask(_ task: URLSessionTask) {
        dispatchPrecondition(condition: .onQueue(rootQueue))
        //task成功获取任务指标后的行为
        //在RequestTaskMap结构体中处理, 检测是否须要断开request跟task的连接
        let didDisassociate = requestTaskMap.disassociateIfNecessaryAfterGatheringMetricsForTask(task)
        //waitingCompletions闭包来自于task请求成功后设置的后续操做, 若是成功获取任务指标后, 执行后续操做, 至此请求完成
        if didDisassociate {
            waitingCompletions[task]?()
            waitingCompletions[task] = nil
        }
    }

    func didCompleteTask(_ task: URLSessionTask, completion: @escaping () -> Void) {
        dispatchPrecondition(condition: .onQueue(rootQueue))
        //检测是否须要断开request跟task的连接
        let didDisassociate = requestTaskMap.disassociateIfNecessaryAfterCompletingTask(task)
        //若是没有后续逻辑, 直接执行完成回调, 不然把回调保存在waitingCompletions字典中, 等待检查任务指标后再判断是否要断开连接
        if didDisassociate {
            completion()
        } else {
            waitingCompletions[task] = completion
        }
    }

    func credential(for task: URLSessionTask, in protectionSpace: URLProtectionSpace) -> URLCredential? {
        dispatchPrecondition(condition: .onQueue(rootQueue))
        //HTTPS证书处理
        return requestTaskMap[task]?.credential ??
            session.configuration.urlCredentialStorage?.defaultCredential(for: protectionSpace)
    }

    func cancelRequestsForSessionInvalidation(with error: Error?) {
        dispatchPrecondition(condition: .onQueue(rootQueue))
        //当URLSession出错时, 并抛出错误 
        requestTaskMap.requests.forEach { $0.finish(error: AFError.sessionInvalidated(error: error)) }
    }
}
复制代码

10、总结:

  • 整个Session类的做用就是:
    1. 初始化并管理URLSession, 持有SessionDelegate对象管理NSURLSession的相关代理方法。
    2. 初始化不一样Request对象,分为三步:
      • 根据不一样的参数, 派发到不一样方法建立不一样的Request子类对象
      • 使用拦截适配器(包括Session带的默认/全局拦截器 + 每一个Request带的专有拦截器)预处理Request对象
      • 调用Request的方法建立URLSessionTask子类,将Request与URLSessionTask连接配对
    3. 调用resume发送task
    4. 实现RequestDelegate协议提供建立Request对象时的两个控制参数,以及处理重试逻辑
    5. 实现SessionStateProvider协议处理Request跟Task的状态
  • Session只管建立Request, 发送Task, 管理Request跟Task的映射, Request的建立, 响应的处理, 缓存, HTTPS, OAuth2认证等将在后续学习了源码以后再慢慢补全

我的理解记录~若有错误欢迎评论指出,很是感谢~