Alamofire源碼分析:網絡請求的封裝

Alamofire是Swift開發者最熟悉也是最常使用的網絡框架,源碼中應用了Swift這門年輕語言的很多新特性,包括了很多泛型、枚舉、協議及擴展的高級使用。

DataRequest

先來看一個簡單的Alamofire網絡請求:

request(requestUrl, method: .get , parameters: params).responseString{ (responseStr) in
      switch responseStr.result{
          case .success(let value):
                //拿到請求成功的數據做處理
          case .failure(let error):
               //失敗處理
        }
}

request(requestUrl, method: .get , parameters: params)方法返回的是一個DataRequest類型的對象,繼承自Request類,也就是Alamofire封裝的請求類,Request封裝了NSURLSessionTask以及Task的基本的代理方法。接著利用DataRequest的responseString方法將請求回來的二進制數據序列化成字符串類型,而回調回來的responseStr字符串是通過responseStr.result中的枚舉值.success來獲得的,我們接下來就來簡單分析一下這么一個簡單的網絡封裝的工具方法在源碼中是怎么實現的。
注意:此處因為是普通的get、post請求,所以返回的是DataRequest類,如果是下載或者上傳,則需要調用download或upload方法,返回的則是DownloadRequest或UploadRequest類)。

先看request方法的封裝實現:

// MARK: - Data Request
    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)
            return request(encodedURLRequest) //調用下方的方法
        } catch {
            return request(originalRequest, failedWith: error)
        }
    }
    
    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)
        }
    }

下面來看看關鍵的網絡請求完成并且序列化數據的封裝方法,也就是上面代碼中的responseString是如何實現的,DataRequest的擴展中提供了五類方法,用來將response序列化成不同類型的數據,以滿足實際的需要,包括Default、Data、String、JSON對象以及Plist類型,而所有這些擴展都被Alamofire放在了ResponseSerialization.swift這個文件里。

ResponseSerialization

我們以其中的responseString為例,先看源碼:

    /// - returns: The request.
    @discardableResult
    public func responseString(
        queue: DispatchQueue? = nil,
        encoding: String.Encoding? = nil,
        completionHandler: @escaping (DataResponse<String>) -> Void)
        -> Self
    {
        return response(
            queue: queue,
            responseSerializer: DataRequest.stringResponseSerializer(encoding: encoding),
            completionHandler: completionHandler
        )
    }

 //response方法,第二個參數要遵循DataResponseSerializerProtocol
  public func response<T: DataResponseSerializerProtocol>(
        queue: DispatchQueue? = nil,
        responseSerializer: T,
        completionHandler: @escaping (DataResponse<T.SerializedObject>) -> Void)
        -> Self

返回一個response方法的實現,completionHandler是最終網絡返回的閉包回調,繼續傳進去給response方法。先看第二個參數 responseSerializer,要遵循DataResponseSerializerProtocol這個協議,此處傳入 DataRequest.stringResponseSerializer(encoding: encoding),進入這個方法:

extension DataRequest {
    /// Creates a response serializer that returns a result string type initialized from the response data with
    /// - returns: A string response serializer.
    public static func stringResponseSerializer(encoding: String.Encoding? = nil) -> DataResponseSerializer<String> {
        return DataResponseSerializer { _, response, data, error in
            return Request.serializeResponseString(encoding: encoding, response: response, data: data, error: error)
        }
    }

就是 通過調用這個方法 返回一個 DataResponseSerializer結構體。

DataResponse

再來看看DataResponseSerializer,他遵循 DataResponseSerializerProtocol,在初始化init方法中:

public struct DataResponseSerializer<Value>: DataResponseSerializerProtocol {
    public typealias SerializedObject = Value

    /// A closure used by response handlers that takes a request, response, data and error and returns a result.
    public var serializeResponse: (URLRequest?, HTTPURLResponse?, Data?, Error?) -> Result<Value>

    public init(serializeResponse: @escaping (URLRequest?, HTTPURLResponse?, Data?, Error?) -> Result<Value>) {
        self.serializeResponse = serializeResponse 
    }
}

給自己的serializeResponse閉包賦值(此處閉包的返回值 在不同的response序列化數據類型中 根據情況 使用,并返回不同的Result),而上面的這個方法:

  //返回值正是Result<String>
 return Request.serializeResponseString(encoding: encoding, response: response, data: data, error: error)
//實現方法
 public static func serializeResponseString(
        encoding: String.Encoding?,
        response: HTTPURLResponse?,
        data: Data?,
        error: Error?)
        -> Result<String>

該返回值Result<String>就是網絡請求成功后處理完的返回值,也是我們最終需要得到的結果,那上面這個DataResponseSerializer的閉包又是在哪返回的Result呢,再回到這個函數:

  return response(
            queue: queue,
            responseSerializer: DataRequest.stringResponseSerializer(encoding: encoding),
            completionHandler: completionHandler
        )

就是在response方法中處理的,來看具體實現:

 public func response<T: DataResponseSerializerProtocol>(
        queue: DispatchQueue? = nil,
        responseSerializer: T,
        completionHandler: @escaping (DataResponse<T.SerializedObject>) -> Void)
        -> Self
    {
        //確保在網絡請求成功后再處理后續操作
        delegate.queue.addOperation {
            //調用responseSerializer的閉包,進行處理獲得result結果
            let result = responseSerializer.serializeResponse(
                self.request,
                self.response,
                self.delegate.data,
                self.delegate.error
            )

          //初始化一個dataResponse,并回調出去
            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
    }

上面的delegate.queue.addOperation {} 保證了這個operation會在網絡請求成功后再執行,然后通過調用let result = responseSerializer.serializeResponse(...),閉包屬性responseSerializer的返回值為Result,最后將dataResponse通過dcompletionHandler(dataResponse) 回調出去,而dataResponse

public struct DataResponse<Value> {
    public init(
        request: URLRequest?,
        response: HTTPURLResponse?,
        data: Data?,
        result: Result<Value>,
        timeline: Timeline = Timeline())
    {
        self.request = request
        self.response = response
        self.data = data
        self.result = result     //最終我們需要的序列化好的數據Result<Value>
        self.timeline = timeline
    }
}

而這個Result<Value>就是個枚舉,利用了泛型,例如網絡請求返回的不同類型的結果(Data、String),結構如下:

public enum Result<Value> {
    case success(Value)
    case failure(Error)  
}

以上就是Alamofire中一個簡單網絡請求封裝的過程,通過源碼解析也一定程度上將Swift的網絡請求知識點再鞏固了一遍。

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容