Alamofire-从一个简单的请求深入源代码(5-完)

2017-10-14  本文已影响27人  yww

Alamofire.request

request 函数签名

request 函数实现

SessionManager.default

SessionManager.default.request

接收响应

数据处理

之前的那个实例代码中, 我们还差一句没讲到的, 怕有些同学已经忘了, 这里再贴一下

Alamofire.request("https://httpbin.org/get").responseString { (response) in
    if let string = response.result.value {
        print(string)
    }
}

对的, 你已经看到了, 就是最后一节的 responseString.
你觉得很奇怪, 因为上一篇中, 我们已经分析到请求结束了, 并没有调用这个函数, 那这一句是怎么调用的?
上篇结尾中, 我们留了一点, 就是 TaskDelegate 中的 OperationQueue. 聪明的你或许已经猜到了, 后续的数据处理, 都是在这个 OperationQueue 中处理的.
我们来看看这个 responseString

extension DataRequest {
    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
        )
    }
}

首先, 需要注意到的是, 这里的返回值, 也是一个 Request 类型的, 也就是说, 这里也是可以使用链式调用, 同时设置多个处理结果的闭包.
然后看到这个函数体, 内部也是在调用一个 response 函数, 我们去看看

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
}

大概可以看出, 也是只有两步, 第一步, 往队列中添加一个操作, 第二步, 返回自身, 以便实现链式调用.
重点都在这个队列的添加操作里面
队列中添加的闭包里面, 也是大概分为三步

  1. 序列化结果
  2. 使用序列化结果生成相应
  3. 调用完成请求闭包.

其中第一步是序列化结果, 例如我们这里将结果序列化为一个字符串.
序列化器是一个遵循 DataResponseSerializerProtocol 协议的泛型. 我们来看看这个协议

public protocol DataResponseSerializerProtocol {
    associatedtype SerializedObject
    var serializeResponse: (URLRequest?, HTTPURLResponse?, Data?, Error?) -> Result<SerializedObject> { get }
}

协议中绑定了一个关联类型 SerializedObject 用来存储结果的类型.
除此之外, 还有一个闭包属性, 这个闭包就是在队列中调用的序列化函数. 这个闭包返回的类型是一个 Result 类型
序列化数据, 只有两种情况, 成功或是失败. Result 类型就是用来存储序列化结果的

public enum Result<Value> {
    case success(Value)
    case failure(Error)
    ... 还有一些可以直接获取结果的便捷属性
}

接下来我们来看看响应是如何被序列化为字符串的
可以在之前的 responseString 函数中看到, 调用的序列化器是
DataRequest.stringResponseSerializer(encoding: encoding)
我们来看看

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

可以看到, 其实这里调用了另一个类型

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

DataResponseSerializer 只是序列化协议DataResponseSerializerProtocol 的一个简单的泛型实现, 通过构造函数而实现了对内部闭包属性的初始化
我们继续回到stringResponseSerializer 函数中, 闭包里面又调用了 Request.serializeResponseString(encoding: encoding, response: response, data: data, error: error) } 来完成实际的序列化, 我们j进去看看

public static func serializeResponseString(
    encoding: String.Encoding?,
    response: HTTPURLResponse?,
    data: Data?,
    error: Error?)
    -> Result<String>
{
    guard error == nil else {
        return.failure(error!) 
    }
    if let response = response, emptyDataStatusCodes.contains(response.statusCode) { 
        return .success("") 
    }
    guard let validData = data else {
        return .failure(AFError.responseSerializationFailed(reason: .inputDataNil))
    }
    var convertedEncoding = encoding
    if let encodingName = response?.textEncodingName as CFString!, convertedEncoding == nil {
        convertedEncoding = String.Encoding(rawValue: CFStringConvertEncodingToNSStringEncoding(
            CFStringConvertIANACharSetNameToEncoding(encodingName))
        )
    }
    let actualEncoding = convertedEncoding ?? String.Encoding.isoLatin1
    if let string = String(data: validData, encoding: actualEncoding) {
        return .success(string)
    } else {
        return .failure(AFError.responseSerializationFailed(reason: .stringSerializationFailed(encoding: actualEncoding)))
    }
}

序列化过程首先是判断是否有错误, 有错误就不用序列化了.
然后判断是否是空白响应, 如果是的话, 就直接返回空字符串
接下来获取数据, 如果获取数据失败, 则返回错误.
获取到数据之后, 需要指定解码用的编码, 如果调用者没有指定, 那么就根据返回头中的编码来解码, 或者是使用默认的"ISO-8859-1" 编码解码
最后则是解码, 发生错误则返回错误, 否则成功
到这里, 字符串就成功解码了, 并封装为Result 类型了.
接下来就是生成相应返回给调用者了.
到这里, 这个简单的请求, 从构造请求, 到接收数据, 检验, 到最终序列化我们就简单的讲完了.
其实还有很多没有涉及到, 例如这只是一个简单的数据请求, 如果是上传或者下载请求呢? 还有 https 的验证我们也没有讲.
Alamofire 无疑是一个非常优秀的框架, 我们可以通过框架大大的简化代码. 如果需要, 同时, 如果我们要使用序列化, 验证等功能, 都可以很容易的做到.

上一篇下一篇

猜你喜欢

热点阅读