Swift - Alamofire源码解析

Posted iOS_developer_zhong

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Swift - Alamofire源码解析相关的知识,希望对你有一定的参考价值。


Alamofire源码解析

解析版本: Alamofire V4.8.0

在使用Swift开发过程中,大家肯定都接触过这个网络请求框架,让我们的网络请求任务变得容易, 这个框架非常简单好用也易于封装,也会基于这个框架做一些自己的封装,比如加上自己的缓存方案等。本篇博客开始对他的源码进行一个解析,不到位处勿喷!!!


一、Alamofire目录结构


一共有17个类。 我会着重其中几个核心的地方,进行一个源码探索。
上面的17个类是什么意思呢,大概说下:

文件作用
AFError错误处理、错误合集、错误分类
Alamofire对外的请求入口,请求、下载、上传、多文件上传
DispatchQueue+Alamofire队列的扩展
MultipartFormData多表单数据处理
NetworkReachabilityManager网络环境监测工具
Notifications通知名称列举
ParameterEncodingURL、JSON、PropertyList Encoding编码处理
Request定义请求类型,(普通,上传,多文件上传,下载)
Response响应数据处理
ResponseSerialization响应数据的序列化
Result结果枚举类,请求结果的成功或者失败
ServerTrustPolicy证书验证类,解决客户端与服务器的信任问题
SessionDelegate处理Session的回调
SessionManager创建各种请求(普通,上传,多文件上传,下载)
TaskDelegate定义多重Delegate,处理URLSessionTask delegate回调
Timeline负责请求中时间节点的处理
Validation验证请求的方式 (比如根据返回的code,判定成功)

二、使用的基本流程 (不讲解基本使用,从源码解析)

基本网络请求使用的代码:

// request,根据项目的需求去组装请求的内容后,生成的 URLRequest
Alamofire.request(request).responseJSON(completionHandler:  (response) in 


1. 发起请求的源码 (举例:普通请求流程)

// 普通请求
public func request(
    _ url: URLConvertible,
    method: HTTPMethod = .get,
    parameters: Parameters? = nil,
    encoding: ParameterEncoding = URLEncoding.default,
    headers: HTTPHeaders? = nil)
    -> DataRequest

    return SessionManager.default.request(
        url,
        method: method,
        parameters: parameters,
        encoding: encoding,
        headers: headers
    )

  1. 当我们发起一个普通请求后,就会调用Alamofire类中定义的 request方法,当然不止这一个方法,还有 download, upload, stream等方法, 返回的结果是 SessionManager所管理的,根据调用的方法不同,依次返回的对象为: DataRequestDownloadRequestUploadRequestStreamRequest
  2. 源码中 : SessionManager.defaultdefault 这是个单例对象, 这个对象很重要, 里面做了很多重要的工作。

2. SessionManager 的关键点解析

// 单例
    public static let `default`: SessionManager = 
        let configuration = URLSessionConfiguration.default
        configuration.httpAdditionalHeaders = SessionManager.defaultHTTPHeaders

        return SessionManager(configuration: configuration)
    ()
    
// 初始化做了那些工作
       public init(
        configuration: URLSessionConfiguration = URLSessionConfiguration.default,
        delegate: SessionDelegate = SessionDelegate(),
        serverTrustPolicyManager: ServerTrustPolicyManager? = nil)
    
     //1. 自己的delegate指向为新建的SessionDelegate()
        self.delegate = delegate
	//2.  创建一个URLSession , 并将 URLSession的代理指向了 SessionDelegte 
        self.session = URLSession(configuration: configuration, delegate: delegate, delegateQueue: nil)

        commonInit(serverTrustPolicyManager: serverTrustPolicyManager)
    

    private func commonInit(serverTrustPolicyManager: ServerTrustPolicyManager?) 
        session.serverTrustPolicyManager = serverTrustPolicyManager
         
        // 3. sessionDelegate 的 sessionManager 又指回了当前self, 它的内部 sessionManager为 weak,不然会有循环引用的问题, 
        delegate.sessionManager = self

        delegate.sessionDidFinishEventsForBackgroundURLSession =  [weak self] session in
            guard let strongSelf = self else  return 
            DispatchQueue.main.async  strongSelf.backgroundCompletionHandler?() 
        
    
     

通过上面的源码说明: 现在我们知道了

  1. URLSession的代理指向了 SessionDelegte
  2. sessionDelegateManager = 当前 sessionManager
    这里使用了代理转换,每个类处理专门的事情。

3. SessionManager , 发起请求关键代码

    @discardableResult
    open func request(
        _ url: URLConvertible,
        method: HTTPMethod = .get,
        parameters: Parameters? = nil,
        encoding: ParameterEncoding = URLEncoding.default,
        headers: HTTPHeaders? = nil)
        -> DataRequest
    
        var originalRequest: URLRequest?

        do 
            originalRequest = try URLRequest(url: url, method: method, headers: headers)
            // 对参数进行编码
            let encodedURLRequest = try encoding.encode(originalRequest!, with: parameters)
            // 调用request请求
            return request(encodedURLRequest)
         catch 
            return request(originalRequest, failedWith: error)
        
    
    
    /// - returns: The created `DataRequest`.
    @discardableResult
    open func request(_ urlRequest: URLRequestConvertible) -> DataRequest 
        var originalRequest: URLRequest?

        do 
        	//1. 返回 URLRequest 对象 ,判断为空的目的
            originalRequest = try urlRequest.asURLRequest()
            // 2. Requestable赋值,  dataRequest继承与 request 
            let originalTask = DataRequest.Requestable(urlRequest: originalRequest!)
             //3.  task 为 URLSessionDataTask 
            let task = try originalTask.task(session: session, adapter: adapter, queue: queue)
            // 4.  初始化DataRequest
            let request = DataRequest(session: session, requestTask: .data(originalTask, task))
			// 5. 用URLSessionTask的identity作为Key, dataRequest为value. 
            delegate[task] = request
			
			//  startRequestsImmediately 默认为true, 交于request中的task 开始执行网络请求 
            if startRequestsImmediately  request.resume() 

            return request
         catch 
            return request(originalRequest, failedWith: error)
        
    

// Request.swift文件中的 
    init(session: URLSession, requestTask: RequestTask, error: Error? = nil) 
        self.session = session

        switch requestTask 
        case .data(let originalTask, let task):
         // 1. 初始化DataTaskDelegate ,并指向给 taskDelegate 
            taskDelegate = DataTaskDelegate(task: task)
            self.originalTask = originalTask
        case .download(let originalTask, let task):
            taskDelegate = DownloadTaskDelegate(task: task)
            self.originalTask = originalTask
        case .upload(let originalTask, let task):
            taskDelegate = UploadTaskDelegate(task: task)
            self.originalTask = originalTask
        case .stream(let originalTask, let task):
            taskDelegate = TaskDelegate(task: task)
            self.originalTask = originalTask
        

        delegate.error = error
        delegate.queue.addOperation  self.endTime = CFAbsoluteTimeGetCurrent() 
      

大致流程为:
初始化 DataRequest ,并将 URLSession 指向 DataRequest,初始化DataTaskDelegate,指向 DataTaskDelegate的taskDelegate , 然后 SessionDelegate 以URLSessionDataTask的identity做为key,DataRequest作为value存储起来。 然后 交于request中的task 开始执行网络请求。

4. SessionDelegate , 收到请求关键代码

    open func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive data: Data) 
        if let dataTaskDidReceiveData = dataTaskDidReceiveData 
            dataTaskDidReceiveData(session, dataTask, data)
         else if let delegate = self[dataTask]?.delegate as? DataTaskDelegate    // 根据task的 indentity,获取到 taskDelegate ,然后执行接收到数据
            delegate.urlSession(session, dataTask: dataTask, didReceive: data)
        
     


// 已经完成了本次网络请求,所调用的方法 
open func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) 
        
        let completeTask: (URLSession, URLSessionTask, Error?) -> Void =  [weak self] session, task, error in
            guard let strongSelf = self else  return 
            // 1. 执行这个闭包
            strongSelf.taskDidComplete?(session, task, error)
            // 2. 执行TaskDelegate中的urlsession ,里面逻辑是和下载有关。
            strongSelf[task]?.delegate.urlSession(session, task: task, didCompleteWithError: error)

            var userInfo: [String: Any] = [Notification.Key.Task: task]
            // 3. 拿到TaskDelegate中的 data (mutableData)
            if let data = (strongSelf[task]?.delegate as? DataTaskDelegate)?.data 
                userInfo[Notification.Key.ResponseData] = data
            

           // 4. 暂时没有用到,通过通知把数据发送出去,使用者去监听这个通知可拿到数据
            NotificationCenter.default.post(
                name: Notification.Name.Task.DidComplete,
                object: strongSelf,
                userInfo: userInfo
            )

            strongSelf[task] = nil
        

        // 出错处理。 
        guard let request = self[task], let sessionManager = sessionManager else 
            completeTask(session, task, error)
            return
        
        
        if let retrier = retrier, let error = error 
           /* 省略若干代码*/
         else 
            // 执行上面的block 
            completeTask(session, task, error)
        
    
    
  1. SessionDelegate 接收到服务器数据返回后, 就会交于到 taskDelegate, 这个delegate,也是第三点中, 通过task的identity,存储到 sessionDelegate中, 这时候再拿出来对应的 taskDelegate 。

5. TaskDelegate , 收到请求的关键代码

    func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive data: Data) 
        if initialResponseTime == nil  initialResponseTime = CFAbsoluteTimeGetCurrent() 

        if let dataTaskDidReceiveData = dataTaskDidReceiveData 
            dataTaskDidReceiveData(session, dataTask, data)
         else 
            if let dataStream = dataStream 
                dataStream(data)
             else   // 1. 把接收到的数据放到了mutableData成员变量中。 
                mutableData.append(data)
            
	
	        // 进度计算, 暂时不管
            let bytesReceived = Int64(data.count)
            totalBytesReceived += bytesReceived
            let totalBytesExpected = dataTask.response?.expectedContentLength ?? NSURLSessionTransferSizeUnknown

            progress.totalUnitCount = totalBytesExpected
            progress.completedUnitCount = totalBytesReceived

            if let progressHandler = progressHandler 
                progressHandler.queue.async  progressHandler.closure(self.progress) 
            
        
    
    

5. 数据序列化的工作。 ResponseSerialization类,关键代码

    public static func serializeResponseJSON(
        options: JSONSerialization.ReadingOptions,
        response: HTTPURLResponse?,
        data: Data?,
        error: Error?)
        -> Result<Any>
    
        guard error == nil else  return .failure(error!) 
         // 1. 判断数据是否为空, 根据状态码
        if let response = response, emptyDataStatusCodes.contains(response.statusCode)  return .success(NSNull()) 
        //2. 判断数据是否为空,根据内容长度
        guard let validData = data, validData.count > 0 else 
            return .failure(AFError.responseSerializationFailed(reason: .inputDataNilOrZeroLength))
        

        do   //3. data转json 数据。 
            let json = try JSONSerialization.jsonObject(with: validData, options: options)
            //4.回调转化成json数据给调用者
            return .success(json)
         catch 
            return .failure(AFError.responseSerializationFailed(reason: .jsonSerializationFailed(error: error)))
        
    
    

我们在来回顾下调用方法,

// request,根据项目的需求去组装请求的内容后,生成的 URLRequest
Alamofire.request(request).responseJSON(completionHandler:  (response) in 


这里可能有个疑问,为什么这里可以使用链式调用, 这里因为 Alamofire.request(request) 返回的是一个DataRequest对象,而responseJSON,是对DataRequest的扩展,所以可以直接调用。


总结

上面说的还很绕的,我通过打断点,追流程,大概总结下,发送一个普通请求,到底经过了那些步骤

  1. Alamofire.swift 文件中的方法 ,对外的request方法
@discardableResult
public func request(_ urlRequest: URLRequestConvertible) -> DataRequest  
  1. SessionManager.swift文件中的方法 ,内部的 request方法
    @discardableResult
    open func request(_ urlRequest: URLRequestConvertible) -> DataRequest  
  1. request.swift文件中的方法 ,发送request网络请求
open func resume() 
  1. SessionDelegate.swift文件中的方法, 网络回调数据
    open func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive data: Data)  
  1. TaskDelegate.swift文件中的方法, 数据存储,进度计算
    func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive data: Data)  
  1. SessionDelegate.swift 文件中的方法, 本次网络请求结束 ,相关的处理
open func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?)  
  1. ResponseSerialization.swift文件中的方法 , 数据的序列化处理
public static func jsonResponseSerializer(
        options: JSONSerialization.ReadingOptions = .allowFragments)
        -> DataResponseSerializer<Any>  
  1. 处理好的json数据 闭包 ( Result : 成功或者失败)传递给调用者。


上面有个疑问? 网络数据完毕后,是如何跑到序列化闭包里面,并返回数据?

这里用到了队列,提前将网络数据装入了队列中,网络数据接收完毕后,再调用起队列,执行任务。

核心的位置: 除了delegate任务分离外, 还有 队列任务用的很巧妙。

在还没有收到网络数据返回前,就将response里面的相关数据, 以闭包的方式加入到 OperationQueue ,代码如下:

//1. TaskDelegate.swift  OperationQueue的初始化, 默认任务是挂起的, 这里很重要
init(task: URLSessionTask?)   
        _task = task

        self.queue = 
            let operationQueue = OperationQueue()

            operationQueue.maxConcurrentOperationCount = 1
            // 1. 默认任务挂起
            operationQueue.isSuspended = true
            operationQueue.qualityOfService = .utility

            return operationQueue
        ()
    

// 2. ResponseSerialization.swift中把 response相关数据打包成block,并放入队列中,等待后面队列的调用。 
@discardableResult
    public func response<T: DataResponseSerializerProtocol>(
        queue: DispatchQueue? = nil,
        responseSerializer: T,
        completionHandler: @escaping (DataResponse<T.SerializedObject>) -> Void)
        -> Self
    
        // 
        delegate.queue.addOperation 
            let result = responseSerializer.serializeResponse(
                self.request,
                self.response,
                self.delegate.data,
                self.delegate.error
            )

            var dataResponse = DataResponse<T.SerializedObject>(
                request: self.request,
                response: self.response,
                data: self.delegate.data,
                result: result,
                timeline: self.timeline
            )

            dataResponse.add(self.delegate.metrics)

            (queue ?? DispatchQueue.main).async  completionHandler(dataResponse) 
        

        return self
    

// 3. 队列的激活, SessionDelegate 中调用完成本次网络请求的回调方法中调用了 TaskDelegate 

// sessionDelegate.swift 网络返回数据结束

```swift
open func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?)  

// TaskDelegate.swift 激活队列

@objc(URLSession以上是关于Swift - Alamofire源码解析的主要内容,如果未能解决你的问题,请参考以下文章

Swift - Alamofire源码解析

Swift - Alamofire源码解析

Swift - Alamofire - 解析 JSON

swift、Alamofire、SwiftyJSON:如何解析 arrayObject

在 Swift 中将 Alamofire 结果解析为对象(使用:Alamofire、SwiftyJSON 和 ObjectMapper)

需要帮助使用 Alamofire 使用 Swift 解析 JSON