关于 Swift 中的 URLSession 和 Alamofire 源码阅读

URLSession/NSURLSession

URLSession至关于管理一个请求的类,它涉及到URL/URLRequest/URLSessionConfiguration/URLSessionTask。经过这几个类的综合使用,咱们就能够很方便的建立请求javascript

建立GET请求

let userTel = "13231852031"
let userPassword = "123456"
let defaultConfiguration = URLSessionConfiguration.default
let sessionWithoutADelegate = URLSession(configuration: defaultConfiguration)
if let url = URL(string: "http://127.0.0.1:8080/v1/login?usertel=\(userTel)&userpassword=\(userPassword)") {
    (sessionWithoutADelegate.dataTask(with: url) { (data, response, error) in
        if let error = error {
            print("Error: \(error)")
        } else if let response = response,
            let data = data,
            let string = String(data: data, encoding: .utf8) {
            print("Response: \(response)")
            print("DATA:\n\(string)\nEND DATA\n")
        }
    }).resume()
}复制代码

建立POST请求

let defaultConfiguration = URLSessionConfiguration.default
let sessionWithoutADelegate = URLSession(configuration: defaultConfiguration)
let paramer: [String: String] = ["userTel":"13231852031","userPassword":"123456"]

if let url = URL(string: "http://127.0.0.1:8080/v1/register") {
    var request = URLRequest.init(url: url)
    request.httpMethod = "POST"
    request.httpBody = try? JSONSerialization.data(withJSONObject: paramer, options: JSONSerialization.WritingOptions.prettyPrinted)

    sessionWithoutADelegate.dataTask(with: request, completionHandler: { (data, response, error) in
        if let error = error {
            print("Error:\(error)")
        }else if let response = response,
            let data = data,
            let string = String(data: data,encoding: .utf8){
            print("Response: \(response)\n")
            print("DATA:\(string)\n")
        }
    }).resume()
}复制代码

根据Alamofire的README读其源码

Swift版本和Alamofire版本

  • Swift:3.0
  • Alamofire:4.4.0

Making a Request

Alamofire.request("https://httpbin.org/get")复制代码

首先,文档中给出上面的一个例子,咱们能够看到很简单就发送了一个请求。接下来咱们能够看一下Alamofire是如何实现的request,经过跳转咱们能够看到该方法是实如今Alamofire.swift文件中:html

@discardableResult
public func request(
    _ url: URLConvertible,
    method: HTTPMethod = .get,
    parameters: Parameters? = nil,
    encoding: ParameterEncoding = URLEncoding.default,
    headers: HTTPHeaders? = nil)
    -> DataRequest
{
    return SessionManager.default.request(
        url,
        method: method,
        parameters: parameters,
        encoding: encoding,
        headers: headers
    )
}复制代码

首先该方法经过URLConvertible协议来判断URL的有效性(如未无效URL会抛出Error),而后方法默认为GET,parameters参数默认为空,参数编码默认为URLEncoding.default,header默认为空。在该方法中又调用了SessionManager,接下来咱们再跳转到SessionManager,在SessionManager中的request方法实现以下(因为方法较长下面代码只贴关键部分):java

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)
}复制代码

在上述实现中咱们能够看到,若是各项参数都没问题的话,它会进入do代码块中request方法.
do中的request方法实现以下:ios

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)
}复制代码

仍是在判断各项参数都正确后调用resume方法,在该方法中它会调用URLSessionTask的resume()来启动该次请求。由此咱们能够看出虽然咱们只是调用这么简单的一句话,可是里面仍是由不少条件和逻辑的,只不过这一切Alamofire替咱们作了。git

上述的代码逻辑若是把全部的错误检查和判断逻辑简化掉,相似于下方的代码:github

let url = URL.init(string: "http://example.com")
let session = URLSession.shared
session.dataTask(with: url!).resume()复制代码

Response Handling

Alamofire默认有五种response handler:编程

  • Response Handler - Unserialized Response(没有序列化response)
  • Response Data Handler - Serialized into Data(将数据序列化为Data)
  • Response String Handler - Serialized into String(将数据序列化为String)
  • Response JSON Handler - Serialized into Any(将数据序列化为Any)
  • Response PropertyList (plist) Handler - Serialized into Any(同上)

Tip:上述五种response handler都没对返回数据的HTTPURLResponse作验证,Alamofire是经过Response Validation作验证的。json

Response Handler
Alamofire.request("https://httpbin.org/get").response { response in
}复制代码

ResponseSerialization.swift中的方法实现:swift

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)
    }复制代码

DefaultDataResponse为结构体,包含request、response、data等数据。api

Alamofire不建议使用这种response serializers。

Response Data Handler
Alamofire.request("https://httpbin.org/get").responseData { response in
}复制代码

若是请求数据和解析数据的过程当中没有发生错误,它将返回一个Data类型的数据,Response的Result将会是.success。在该方法的实现源码中调用了responseSerializer: DataRequest.dataResponseSerializer()序列化数据的方法

Response String Handler
Alamofire.request("https://httpbin.org/get").responseString { response in
}复制代码

该Handler经过responseStringSerializer将返回的Data数据转为String类型,若是没有错误发生,而且服务器数据成功转为String,response的Result将为.success而且值为String。

Response JSON Handle
Alamofire.request("https://httpbin.org/get").responseJSON { response in
}复制代码

该handler经过调用jsonResponseSerializer方法来转换数据类型,若没发生错误request同上

Chained Response Handlers

Tip:使用链式response包含几个handler,就会请求几回数据数据

Response Handler Queue

Response handlers默认在主线程队列中执行,可是咱们能够提供一个自定义线程队列

Response Validation

默认状况下,Alamofire认为任何已完成的请求都是成功的,不管相应内容是什么。你能够在handler以前调用validate来判断status code

HTTP Methods

Alamofire支持HTTP的GET、POST、DELETE等方法,并将这些方法声明为HTTPMethod的enum

Parameter Encoding

Alamofire提供三种参数编码方式URL,JSON和PropertyList

Session Manager

SessionManager.swift是Alamofire中比较重要的一个文件,它是URLSession的管理类,文件中是对request方法的具体实现。正是有该类才使得Alamofire发起一个请求很是简单。
经过源码咱们能够看见若是不设置URLSessionConfiguration,默认为URLSessionConfiguration.default
你也能够将URLSessionConfiguration修改成Background Configuration和Ephemeral Configuration

Request

Requests能够被暂停(suspended)复位(resumed)和取消(cancelled)

Routing Requests

随着APP的不断更新和迭代,构建网络层的通用模式很重要。如何路由你的request也是很是重要的一个部分。URLConvertibleURLRequestConvertible协议能够帮助你构建路由的通用部分

URLConvertible

String, URL, 和URLComponents是默认遵照URLConvertible协议的,因此你能够在request中写String, URL, 和URLComponents,它会自动检测request中的参数,根据参数类型找到相应的方法转为URL。你也能够根据文档中的例子来构造本身的路由

URLRequestConvertible

URLRequest默认遵照该协议,该协议用来构造URLRequest

代码中的关键字解释

  • @discardableResult:此关键字表示修饰的方法没必要接受返回值Swift 3.0 中方法的返回值必须有接收不然会报警告,固然其实主要目的是为了不开发人员忘记接收返回值的状况,可是有些状况下确实不须要使用返回值可使用"_"接收来忽略返回值。固然你也能够增长@discardableResult声明,告诉编译器此方法能够不用接收返回值
  • open:open 一个元素在其余module中仍是能够被override
  • static:在方法的func关键字以前加上关键字static或者class均可以用于指定类方法.不一样的是用class关键字指定的类方法能够被子类重写
  • @escaping

总结

至此,Alamofire的源码已经了解完,我在这里只是简单的了解一下Alamofire是如何实现最基本的GET和POST请求如何实现。能够看到,它经过几层包装实现了参数的校验、request支持String、URL和URLComponents三种方式。因为水平有限,对于它下载上传等功能的源码并无十分理解,因此在这并无写,你们有能力的能够自行查看源码。在Alamofire中比较重要的几个文件Alamofire.swift/Response.swift/SessionManager.swift/Request.swift。

github地址

参考

相关文章
相关标签/搜索