Alamofire Response源码解读

2019-08-27  本文已影响0人  盾子

前言

Alamofire设计了2种与Request相对应的Response类型,他们分别是:

Response流程分析

先看一段简单代码

SessionManager.default
    .request(urlString)
    .response { (response) in
        print(response)
    }
    .responseJSON { (jsonResponse) in
        print(jsonResponse)
}
public func response(queue: DispatchQueue? = nil, completionHandler: @escaping (DefaultDataResponse) -> Void) -> Self {
    delegate.queue.addOperation {
        (queue ?? DispatchQueue.main).async {
            var dataResponse = DefaultDataResponse(
                request: self.request,
                response: self.response,
                data: self.delegate.data,
                error: self.delegate.error,
                timeline: self.timeline
            )

            dataResponse.add(self.delegate.metrics)

            completionHandler(dataResponse)
        }
    }

    return self
}
self.queue = {
    let operationQueue = OperationQueue()

    operationQueue.maxConcurrentOperationCount = 1
    operationQueue.isSuspended = true
    operationQueue.qualityOfService = .utility

    return operationQueue
}()
func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) {
    if let taskDidCompleteWithError = taskDidCompleteWithError {
        taskDidCompleteWithError(session, task, error)
    } else {
        // 省略无关代码......
        queue.isSuspended = false
    }
}

DefaultDataResponse

把目光移到response方法,创建了一个DefaultDataResponse对象并作为completionHandler的参数回调出去。

public struct DefaultDataResponse {
    /// 表示该响应来源于那个请求
    public let request: URLRequest?

    /// 服务器返回的响应
    public let response: HTTPURLResponse?

    /// 响应数据
    public let data: Data?

    /// 在请求中可能发生的错误
    public let error: Error?

    /// 请求的时间线封装
    public let timeline: Timeline
    
    /// 包含了请求和响应的统计信息
    var _metrics: AnyObject?
}
var dataResponse = DefaultDataResponse(
    request: self.request,
    response: self.response,
    data: self.delegate.data,
    error: self.delegate.error,
    timeline: self.timeline
)
override var data: Data? {
    if dataStream != nil {
        return nil
    } else {
        return mutableData
    }
}
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 {
            mutableData.append(data)
        }

        // 省略无关代码......
    }
}

DataResponse<Value>

DataResponse<Value>比上边的DefaultDataResponse多了一个public let result: Result<Value>属性,该属性存储了序列化后的数据。接着看看在Alamofire中是如何使用Result的,来到responseJSON方法中:

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
    )
}

DataResponseSerializer

一般来说,我们需要对response.data做序列化处理之后才方便使用。Alamofire已经提供了一些常用的序列化器,可以直接调用api使用。同样也可以自定义序列化器来实现自己功能。下面来看看responseJSON方法时怎么实现的。

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
    )
}
public static func jsonResponseSerializer(
    options: JSONSerialization.ReadingOptions = .allowFragments)
    -> DataResponseSerializer<Any>
{
    return DataResponseSerializer { _, response, data, error in
        return Request.serializeResponseJSON(options: options, response: response, data: data, error: error)
    }
}
public static func serializeResponseJSON(
    options: JSONSerialization.ReadingOptions,
    response: HTTPURLResponse?,
    data: Data?,
    error: Error?)
    -> Result<Any>
{
    guard error == nil else { return .failure(error!) }

    if let response = response, emptyDataStatusCodes.contains(response.statusCode) { return .success(NSNull()) }

    guard let validData = data, validData.count > 0 else {
        return .failure(AFError.responseSerializationFailed(reason: .inputDataNilOrZeroLength))
    }

    do {
        let json = try JSONSerialization.jsonObject(with: validData, options: options)
        return .success(json)
    } catch {
        return .failure(AFError.responseSerializationFailed(reason: .jsonSerializationFailed(error: error)))
    }
}

总结

有问题或者建议和意见,欢迎大家评论或者私信。
喜欢的朋友可以点下关注和喜欢,后续会持续更新文章。

上一篇 下一篇

猜你喜欢

热点阅读