1 原生网络请求与Alamofire区别
先来看看原生的网络请求是怎么样请求的:
let session = URLSession(configuration: .default)
let url = "https://ip.cn"
let request = URLRequest(url: URL(string: url)!)
let task = session.dataTask(with: request) { (data, response, error) in
print(String(bytes: data!, encoding: .utf8)!)
}
task.resume()
再来看看Alamofire是怎么请求的:
Alamofire
.request("https://ip.cn")
.responseData { respons in
print(String(bytes: respons.data!, encoding: .utf8)!)
}
可以看出,Alamofire要简洁很多。然而我们要知道一件事情,Alamofire在请求网络的时候,依然是调用的系统原生的URLSession和URLRequest等,只是Alamofire给我们封装好了要如何调用。
2 揭开Alamofire.request()方法的面纱
2.1 查看Alamofire.request()的源码
@discardableResult //如果不接收本方法的返回值,不会有提示
public func request(
_ url: URLConvertible, //请求的url,符合URLConvertible协议的实例即可
method: HTTPMethod = .get, //请求方法,默认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
)
}
通过源码,可以看出,request()方法内部,实际上是调用了SessionManager单例的request()方法,参数原封不动的传递了过去。
2.2查看SessionManager.default.request()的源码
@discardableResult
open func request(
_ url: URLConvertible, //请求url
method: HTTPMethod = .get, //请求方法
parameters: Parameters? = nil, //请求参数
encoding: ParameterEncoding = URLEncoding.default, //参数编码方式
headers: HTTPHeaders? = nil) //请求头
-> DataRequest //请求实例
{
var originalRequest: URLRequest?
do {
// 通过传递进来的url、method、headers创建出原生的请求
originalRequest = try URLRequest(url: url, method: method, headers: headers)
// 通过给定的编码方式编码参数获得编码过后的请求
let encodedURLRequest = try encoding.encode(originalRequest!, with: parameters)
// 调用自身的request(_ urlRequest: URLRequestConvertible)方法,并返回
return request(encodedURLRequest)
} catch {
return request(originalRequest, failedWith: error)
}
}
可以看出,本方法只是把传入的参数编码,然后生成原生的请求,传递给下一个方法进行处理。本方法还没有发送出请求。
2.3查看SessionManager.default.request(_ urlRequest: URLRequestConvertible)的源码
@discardableResult
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)
}
}
通过源码,可以看出,请求是在本方法中发送出去的。
3 Alamofire请求参数
@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
)
}
本方法中,涉及到Alamofire的内容有:
- URLConvertible
public protocol URLConvertible {
func asURL() throws -> URL
}
可以看到,这是一个协议,这也就是说,传入的url不一定是一个url字符串,只要是遵守了URLConvertible协议的实例就可以。Alamofire帮我们实现了很多,我们直接使用就可以了。如下:
extension String: URLConvertible {
public func asURL() throws -> URL {
guard let url = URL(string: self) else { throw AFError.invalidURL(url: self) }
return url
}
}
extension URL: URLConvertible {
public func asURL() throws -> URL { return self }
}
extension URLComponents: URLConvertible {
public func asURL() throws -> URL {
guard let url = url else { throw AFError.invalidURL(url: self) }
return url
}
}
所以,传入的url可以是String、URL、URLComponents三者之一。当然,我们是可以自定义的只要实现了协议即可。
- HTTPMethod
public enum HTTPMethod: String {
case options = "OPTIONS"
case get = "GET"
case head = "HEAD"
case post = "POST"
case put = "PUT"
case patch = "PATCH"
case delete = "DELETE"
case trace = "TRACE"
case connect = "CONNECT"
}
这个没什么好说的。请求方法列表。默认是GET请求。
- Parameters
public typealias Parameters = [String: Any]
可以看出,参数是字典,key必须是String。默认是nil。
- ParameterEncoding
public protocol ParameterEncoding {
func encode(_ urlRequest: URLRequestConvertible, with parameters: Parameters?) throws -> URLRequest
}
参数编码方式传入的是遵循了ParameterEncoding协议,实现了编码参数方法的实例。默认值URLEncoding.default。
- HTTPHeaders
public typealias HTTPHeaders = [String: String]
请求头也是字典,key和value都是String,默认值是nil。
至此,Alamofire的请求流程全部走了一遍。
4 总结
通过上面的流程,我们可以发现,Alamofire在很多地方是可以按照自己的需求去定制的。包括但不仅限于如下内容:
- 1.可以自定义传入url的类型
- 2.可以自定义传入参数编码的类型,也就可以自定义参数的编码方式
- 3.可以自定义SessionManager
- 4.可以设置任务是否是直接发出,默认是直接发出请求
- 5.可以自定义请求转换方式
网友评论