美文网首页
源码分析-Alamofire

源码分析-Alamofire

作者: 李传格 | 来源:发表于2017-01-24 11:03 被阅读21次

    概述

    • AlamofireAFNetworking的功能差不多,都是对URLSession的封装,对上层提供易用的网络请求接口。

    • AlamofireAFNetworking分别是Swift和OC的实现版本。

    • 目前,这两个网络封装库的关注度和使用率非常高,代码质量也相当不错。本文想通过对Alamofire源码的简单分析,了解其基本框架和设计思路。

    • 源码链接:Alamofire

    一个GET请求的源码分析

    • 从最简单的Get请求入手,分析Alamofire的代码。一个请求流程,可以分为请求发送流程和请求响应流程,下文将从这两个流程展开分析。
    // Get请求的调用方式
    Alamofire.request("https://httpbin.org/get").responseJSON { response in
        print(response.request)  // original URL request
        print(response.response) // HTTP URL response
        print(response.data)     // server data
        print(response.result)   // result of response serialization
    
        if let JSON = response.result.value {
            print("JSON: \(JSON)")
        }
    }
    

    请求发送流程

    • Alamofire.Swift可以认为Alamofire一些对外接口的包装(Facade API)。
      Alamofire.request实际上是调用了SessionManager.request
    // 调用request方法
    /// Creates a `DataRequest` using the default `SessionManager` to retrieve the contents of a URL based on the specified `urlRequest`.
    @discardableResult
    public func request(_ urlRequest: URLRequestConvertible) -> DataRequest {
        return SessionManager.default.request(urlRequest)
    }
    
    • SessionManager.requestRequest被组装创建,并加到发送队列中,然后等待一系列的响应事件。而SessionManager主要职责是管理发送队列,组装请求消息,设置Session相关的配置,设置工作线程等。
    // 创建request对象,并开始发送
    /// Creates a `DataRequest` to retrieve the contents of a URL based on the specified `urlRequest`.
        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)
            }
        }
    
    • 接着,通过Request.responseJSON设置JSON响应回调的处理方法。
    // 设置回调
    /// Adds a handler to be called once the request has finished.
        @discardableResult
        public func responseJSON(
            queue: DispatchQueue? = nil,
            options: JSONSerialization.ReadingOptions = .allowFragments,
            completionHandler: @escaping (DataResponse<Any>) -> Void)
            -> Self
        {
            return response(
                queue: queue,
                responseSerializer: DataRequest.jsonResponseSerializer(options: options),
                completionHandler: completionHandler
            )
        }
    
    • Request.responseJSON实际上是调用Request.response,将回调添加到Request.delegate.queue,然后等待响应事件。
        /// Adds a handler to be called once the request has finished.
        @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
        }
    
    
    • 至此,发送流程完成,接着就等待响应事件。

    请求响应流程

    • 一个请求的响应事件会有多个,并按循序上报,例如以下几个主要事件,

    • HTTPS鉴权事件 func urlSession(_ session: URLSession,task: URLSessionTask, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void)

    • 收到Response响应头事件 func urlSession(_ session: URLSession,dataTask: URLSessionDataTask, didReceive response: URLResponse, completionHandler: @escaping (URLSession.ResponseDisposition) -> Void)

    • 收到Response Body数据事件 func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive data: Data)

    • 响应流程完成事件 func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?)

    • 本文以最后一个响应流程完成事件为例,梳理下整个响应流程。

    • 首先,SessionDelegate会收到由URLSession.delegate上报的urlSession:task:didCompleteWithError,根据task找到URLSessionTask并通过其delegate上报事件给TaskDelegate

        /// Tells the delegate that the task finished transferring data.
        open func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) {
            /// Executed after it is determined that the request is not going to be retried
            let completeTask: (URLSession, URLSessionTask, Error?) -> Void = { [weak self] session, task, error in
                guard let strongSelf = self else { return }
    
                if let taskDidComplete = strongSelf.taskDidComplete {
                    taskDidComplete(session, task, error)
                } else if let delegate = strongSelf[task]?.delegate {
                    delegate.urlSession(session, task: task, didCompleteWithError: error)
                }
    
                NotificationCenter.default.post(
                    name: Notification.Name.Task.DidComplete,
                    object: strongSelf,
                    userInfo: [Notification.Key.Task: task]
                )
    
                strongSelf[task] = nil
            }
    
            guard let request = self[task], let sessionManager = sessionManager else {
                completeTask(session, task, error)
                return
            }
    
            // Run all validations on the request before checking if an error occurred
            request.validations.forEach { $0() }
    
            // Determine whether an error has occurred
            var error: Error? = error
    
            if let taskDelegate = self[task]?.delegate, taskDelegate.error != nil {
                error = taskDelegate.error
            }
    
            /// If an error occurred and the retrier is set, asynchronously ask the retrier if the request
            /// should be retried. Otherwise, complete the task by notifying the task delegate.
            if let retrier = retrier, let error = error {
                retrier.should(sessionManager, retry: request, with: error) { [weak self] shouldRetry, timeDelay in
                    guard shouldRetry else { completeTask(session, task, error) ; return }
    
                    DispatchQueue.utility.after(timeDelay) { [weak self] in
                        guard let strongSelf = self else { return }
    
                        let retrySucceeded = strongSelf.sessionManager?.retry(request) ?? false
    
                        if retrySucceeded, let task = request.task {
                            strongSelf[task] = request
                            return
                        } else {
                            completeTask(session, task, error)
                        }
                    }
                }
            } else {
                completeTask(session, task, error)
            }
        }
    
    • 接着,TaskDelegate收到该事件后,恢复queue队列,按循序执行其中的回调,如ResponseJSON
        @objc(URLSession:task:didCompleteWithError:)
        func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) {
            if let taskDidCompleteWithError = taskDidCompleteWithError {
                taskDidCompleteWithError(session, task, error)
            } else {
                if let error = error {
                    if self.error == nil { self.error = error }
    
                    if
                        let downloadDelegate = self as? DownloadTaskDelegate,
                        let resumeData = (error as NSError).userInfo[NSURLSessionDownloadTaskResumeData] as? Data
                    {
                        downloadDelegate.resumeData = resumeData
                    }
                }
    
                // queue队列中的operaion开始按循序执行,回调到上层。
                queue.isSuspended = false
            }
        }
    

    其他模块

    • 除了发送,响应相关的代码,Alamofire还有许多其他模块。例如,

    • NetworkReachabilityManager管理网络状态。

    • ParameterEncoding 入参编解码方式。

    • ResponseSerialization 响应的反序列化方式。

    • ServerTrustPolicy HTTPS的鉴权

    • 等等。

    总结

    • 分析得比较简单,抱砖引玉。

    相关文章

      网友评论

          本文标题:源码分析-Alamofire

          本文链接:https://www.haomeiwen.com/subject/vuezbttx.html