4fe0923113c070acf37211a60e64c524
Alamofire(3)— Request

😊😊😊Alamofire专题目录,欢迎及时反馈交流 😊😊😊


Alamofire 目录直通车 --- 和谐学习,不急不躁!


上一篇 Alamofire-后台下载 其中就介绍了关于 SesssionManagerSessionDelegate的分层!下面我在总结一下,然后开始一个 Alamofire 非常重要的模块 Request!

一、SessionManager的总结

  • SesssionManager 就是对外提供的管理者,这个管理者具备整个 Alamofire 的所有功能。

    • request 请求、download、upload、stream
    • 请求头信息设置以及多表单头信息设置
    • session 直接对外提供,方便自由处理
    • 初始化暴露,方便自由工厂构造,比如 URLSessionConfiguration 的配置模式
    • 重试以及适配请求
    • 闭包对外提供:backgroundCompletionHandler 后台下载回来监听闭包
    • 其中一个非常重要的点就是 SesssionManagerSession 的代理移交给了一个专门的类 : SessionDelegate
  • SessionDelegate实现了 URLSessionDelegateURLSessionTaskDelegateURLSessionDataDelegateURLSessionDownloadDelegateURLSessionStreamDelegate 等代理

  • 更多有意思的是:`SessionDelegate`还提供了对外的闭包,意味着所有的内部实现的代理情况,再外界都可以进行监听。当然这个所有的对外闭包分为两种情况:
    • 在原来代理回调的内部添加闭包执行。

  • 另一种是二选一,如果代理回来就不执行下层代理下发,执行对外闭包回调

总结:SesssionManager负责创建和管理 Request 对象及其底层NSURLSession

首先给大家贴出一张非常熟悉的图,看懂了这张图对下面理解 Request 的帮助大大的

  • 从上面这张图可以看出,我们的对外模块是SesssionManager,他给外界的用户提供了很多的功能
  • 但是这些工作的真正实现者是由iOS、Android、前端、后台、测试实现的!
  • 其中单拿 iOS 模块的任务来说,有 首页、发现、我的、SDK、视频....模块要实现,但是我们的项目经理有可能都不知道这些到底是什么,怎么实现!所有来说如果全部交给SesssionManager来实现,显然耦合性过强,还有任务乱七八糟,没有体现一个牛逼项目分层架构的效果。所以在 iOS 任务细化和SesssionManager 之间就缺了一个小管理者,对下:他知道具体事务和调度。对上:他能和SesssionManager协调配合。那就是 Request

二、Request

1. Request参数编码

  • 首先说明一下 Alamofire 支持编码格式,具体格式差异根据名字很容易理解,实在不能理解的可以自行百度查漏补缺

    • URLEncoding
    • JSONEncoding
    • PropertyListEncoding
  • let encodedURLRequest = try encoding.encode(originalRequest!, with: parameters) 通过这句代码还编码请求

public func encode(_ urlRequest: URLRequestConvertible, with parameters: Parameters?) throws -> URLRequest {
    var urlRequest = try urlRequest.asURLRequest()

    guard let parameters = parameters else { return urlRequest }

    if let method = HTTPMethod(rawValue: urlRequest.httpMethod ?? "GET"), encodesParametersInURL(with: method) {
        guard let url = urlRequest.url else {
            throw AFError.parameterEncodingFailed(reason: .missingURL)
        }

        if var urlComponents = URLComponents(url: url, resolvingAgainstBaseURL: false), !parameters.isEmpty {
            let percentEncodedQuery = (urlComponents.percentEncodedQuery.map { $0 + "&" } ?? "") + query(parameters)
            urlComponents.percentEncodedQuery = percentEncodedQuery
            urlRequest.url = urlComponents.url
        }
    } else {
        if urlRequest.value(forHTTPHeaderField: "Content-Type") == nil {
            urlRequest.setValue("application/x-www-form-urlencoded; charset=utf-8", forHTTPHeaderField: "Content-Type")
        }
        urlRequest.httpBody = query(parameters).data(using: .utf8, allowLossyConversion: false)
    }
    return urlRequest
}
  • 代码自行查阅,这里总结一下

  • 首先取出请求方法,根据不同的请求方法,参数编码是不同的

    • .get, .head, .delete 这三个方法是把参数直接拼接到 URL 后面
    • 其他通过请求体 (httpBody) 的形式编码
  • 因为我们的请求是通过 ASCII编码 的,所以要进行百分号编码,第一步就是对当前请求的所有路由百分号编码

  • 参数便利编码, 拼接拿出

private func query(_ parameters: [String: Any]) -> String {
    var components: [(String, String)] = []

    for key in parameters.keys.sorted(by: <) {
        let value = parameters[key]!
        components += queryComponents(fromKey: key, value: value)
    }
    return components.map { "\($0)=\($1)" }.joined(separator: "&")
}
  • 通过 ASCII 有小到大进行排序
  • queryComponents 这个方法代码过度省略。
top Created with Sketch.